「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」
在许多开发场景中,我们需要在对类的某些属性进行赋值时进行额外的操作。在Object-C中我们可以通过为属性实现set方法加入一下额外的逻辑。Swift语言中的存储属性提供了属性监听器,以便我们执行相似的操作;
属性监听器
属性监听器用于监听存储属性赋值的过程,并且我们可以在其中编写代码,添加额外的逻辑处理。需要注意的是,在进行属性的构造或者初始化时,无论是通过构造方法进行属性构造或者初始化,还是为属性设置默认值,都不会调用属性监听器的方法。初始化之后第2次为属性赋值开始,才会触发属性监听器; 我们来看一段示例代码:
class Person {
var name: String {
willSet {
print("新名字:\(newValue)")
}
didSet {
print("旧名字:\(oldValue)")
}
}
init(name: String) {
self.name = name
}
}
我们将其生成SIL文件来分析其执行流程:
通过SIL文件分析,我们可以得到一下结论:
调用
name的set方法将会触发willset方法,然后进行name赋值操作,赋值完成之后,触发didset方法;
在初始化时,属性监听器并不会被触发:
我们通过上述代码运行效果,验证了在初始化时,属性监听器并不会被触发,之后再次赋值时,才会再次被触发;(初始化时可以理解为直接操作的内存,而没有调用set方法);
我们上边是给存储属性添加的属性监听器,那么计算属性能否设置属性监听器呢?
给计算属性设置属性监听器将会报错;
只有存储属性可以设置属性监听器,计算属性不可以;
继承关系中的属性监听器
如果子类继承父类,并且重写了父类的属性,那么其属性监听器的执行将会是什么效果呢?
我们编写如下代码:
运行结果如下:
调用顺序为:
- 子类的
willSet - 父类的
willSet - 父类的
didSet - 子类的
didSet
该调用顺序,我们也可以通过SIL文件分析得到:
Teacher的name赋值时将会调用set方法,通过SIL分析Teacher的name属性的set方法可以看到依次调用了:Teacher.name.willset、Person.name.setter和Teacher.name.didset,而Person.name.setter调用中必定先后调用Person.name.willset和Person.name.didset:
我们由此也能验证其调用顺序为:子类的willset、父类的willset、父类的didset以及子类的didset;