swift进阶

swift进阶三:属性 & 属性观察者

2020-12-08  本文已影响0人  markhetao

swift进阶 学习大纲

上一节,我们分析了类的结构,知道属性影响类的大小计算。所以本节,我们分析属性

  1. 存储型属性和计算型属性
  2. 属性观察者(willSetdidSet)
  3. 属性的继承

1. 存储型属性和计算型属性

import Foundation

class Square {
    // 【存储型属性】
    let type: String = "Square"  // let 不可修改
    var width: Double = 8.0      // var 可修改 (有set和get方法,可以存储)
     
    // 【计算型属性】 本质是函数,自身不具备存储功能
    var area: Double {
        get { width * width }             // 函数内容只有一行,默认调用或返回这一行结果
        set { width = sqrt(newValue) }
    }
}

let s = Square()
// s.type = "123"
s.width = 5
print("【修改width】width: \(s.width)")
print("【修改width】area:  \(s.area)")

s.area = 100
print("【修改area】width: \(s.width)")
print("【修改area】area:  \(s.area)")

print("end")

【存储型属性】

  1. let修饰的type属性,是不可修改变量首次赋值后不可修改),只有getter方法
  2. var修饰的width属性,是可修改变量,有getset方法

【计算型属性】

  1. area属性是计算型属性,必须用var修饰。自身不可存储,本质是函数
    存储型属性影响类的大小计算型属性 不影响类的大小
image.png

打开终端cdDemo文件夹,输入swiftc -emit-sil main.swift >> ./main.sil生成main.sil文件。使用VSCode打开。

  1. Square类结构:

    image.png
  2. typegetter方法:

    image.png
  3. widthgetter方法:

    image.png
  4. widthsetter方法:

    image.png
  5. areagetter方法:

    image.png
  6. areasetter方法:

    image.png

SIL中间代码,可以清晰得到如下结论

  1. let修饰的存储型属性可存储,需要初始值,只有get方法。
  2. var修饰的存储型属性可存储,需要初始值,有getset方法
  3. 计算型属性不支持存储,没有,有getset方法,但内部操作本属性无关。等于就是一个便利函数。(本质就是函数,不是属性)

2. 属性观察者

  • willSet: 新值存储前触发
  • didSet: 新值存储后触发
import Foundation

class HTPerson {
    
    var name: String = "ht" {
        willSet {
            print("新值: \(newValue)")
            print("willSet")
        }
        didSet {
            print("didSet")
        }
    }
    
}

let p = HTPerson()
p.name = "学习不行,回家喂猪!"

print("end")
image.png
  • 首先,可以看到name属性是存储型属性,具有setget方法:
image.png
  • 其次,可以看到willSetdidSet都是函数:
image.png image.png
  • 最后,可以看到在set方法中,顺序为willSet->set赋值->didSet
image.png

Q1: 计算型属性是否可以添加属性观察者吗?

A:计算型属性都自定义getset方法了,还有必要willSetdidSet吗?

willSetdidSet本质是在set方法赋值前后进行触发。你直接在set方法自己写不香吗?完全用不到属性观察者

set {   
    1.赋值前你做点啥 (willSet)
    2.赋值操作 
    3.赋值后你想做啥(didSet)
}

Q2: init时,为啥不触发属性观察者

A: swift,是一门非常安全语言。他要求所有属性,必须完成初始赋值后,才可使用
(可选值默认初始值nil)

  • init时,swift会对开辟空间进行数据清空memset),且所有属性都必须有初始值

  • 比如在Init中,计算属性使用到了存储属性,但存储属性未赋值。可能访问到内存旧值脏数据),发生内存错误。这不安全swift不允许不安全因素的存在。 所以所有属性拥有初始值之后,触发属性观察者。

    image.png

3.属性的继承

image.png

属性一般都可继承,除非:

  1. 子类不可重写let属性,但可访问
  2. 子类不可重写和父类不一致属性(计算型改成存储型)

Q: willSet和didSet的继承读取顺序

子类willSet -> 父类willSet -> 父类didSet -> 子类didSet

  • 顾客 : 小孩,我买个锤子?(子类willSet)
  • 小孩: 爸,咱家锤子在哪,给我拿一下!(父类willSet)
  • 爸:好,给你!(父类didSet)
  • 小孩: 先生,你要的锤子(子类didSet)
class HTPerson {
    
    var name: String = "ht"  {
        willSet { print("[HTPerson age] willSet") }
        didSet { print("[HTPerson age] didSet") }
    }

}

class HTStudent: HTPerson {
    
    override var name: String {
        willSet { print("[HTStudent age] willSet") }
        didSet { print("[HTStudent age] didSet") }
    }
    
    override init() {
        super.init() // 如果父类将所有属性都实现了,【子类init时】可正常触发【属性观察者】
        self.name = "ht"
    }
    
}

let p = HTStudent()

print("end")
image.png
上一篇下一篇

猜你喜欢

热点阅读