Swift(十)-属性监听器

810 阅读2分钟

「这是我参与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文件来分析其执行流程:

image.png

通过SIL文件分析,我们可以得到一下结论:

调用nameset方法将会触发willset方法,然后进行name赋值操作,赋值完成之后,触发didset方法;

在初始化时,属性监听器并不会被触发:

iShot2022-01-08 15.55.07.gif

我们通过上述代码运行效果,验证了在初始化时,属性监听器并不会被触发,之后再次赋值时,才会再次被触发;(初始化时可以理解为直接操作的内存,而没有调用set方法);

我们上边是给存储属性添加的属性监听器,那么计算属性能否设置属性监听器呢?

image.png

给计算属性设置属性监听器将会报错;

只有存储属性可以设置属性监听器,计算属性不可以;

继承关系中的属性监听器

如果子类继承父类,并且重写了父类的属性,那么其属性监听器的执行将会是什么效果呢?

我们编写如下代码:

image.png

运行结果如下:

image.png

调用顺序为:

  1. 子类的willSet
  2. 父类的willSet
  3. 父类的didSet
  4. 子类的didSet

该调用顺序,我们也可以通过SIL文件分析得到:

image.png

Teachername赋值时将会调用set方法,通过SIL分析Teachername属性的set方法可以看到依次调用了:Teacher.name.willsetPerson.name.setterTeacher.name.didset,而Person.name.setter调用中必定先后调用Person.name.willsetPerson.name.didset

image.png

我们由此也能验证其调用顺序为:子类的willset父类的willset父类的didset以及子类的didset