12.3 属性观察者

为了监听属性的变化,Swift提供了属性观察者。属性观察者能够监听存储属性的变化,即便变化前后的值相同,它们也能监听到。但它们不能监听延迟存储属性和常量存储属性的变化。

Swift中的属性观察者主要有以下两个。

  • willSet:观察者在修改之前调用。

  • didSet:观察者在修改之后立刻调用。

属性观察者的语法格式如下:

  1. 面向对象类型 类型名 {
  2. ......
  3. var 存储属性 : 属性数据类型 = 初始化值 {
  4. willSet(新值) {
  5. ......
  6. }
  7. didSet(旧值) {
  8. ......
  9. }
  10. }
  11. }

属性观察者的语法格式比计算属性还要混乱,下面我们解释一下。第①行的“面向对象类型”包括类和结构体,不包括枚举,因为枚举不支持存储属性。

代码第②~⑥行是定义存储属性。第②行的“存储属性”是我们定义的存储属性名。

代码第③~④行是定义willSet观察者。第③行代码中的“新值”是传递给willSet观察者的参数,它保存了将要替换原来属性的新值。参数的声明可以省略,系统会分配一个默认的参数newValue

代码第⑤~⑥行是定义didSet观察者。第⑤行代码中的“旧值”是传递给didSet观察者的参数,它保存了被新属性替换的旧值。参数的声明也可以省略,系统会分配一个默认的参数oldValue

示例代码如下:

  1. class Employee {
  2. var no : Int = 0
  3. var name : String = "Tony" {
  4. willSet(newNameValue) {
  5. println("员工name新值:\(newNameValue)")
  6. }
  7. didSet(oldNameValue) {
  8. println("员工name旧值:\(oldNameValue)")
  9. }
  10. }
  11. var job : String?
  12. var salary : Double = 0
  13. var dept : Department?
  14. }
  15. struct Department {
  16. var no : Int = 10 {
  17. willSet {
  18. println("部门编号新值:\(newValue)")
  19. }
  20. didSet {
  21. println("部门编号旧值:\(oldValue)")
  22. }
  23. }
  24. var name : String = "RESEARCH"
  25. }
  26. var emp = Employee()
  27. emp.no = 100
  28. emp.name = "Smith"
  29. var dept = Department()
  30. dept.no = 30

上述代码第①行定义了Employee类,第②行是定义name属性,第③行是定义name属性的willSet观察者,newNameValue是由我们分配的传递新值的参数名,第④行是willSet观察者内部处理代码,其中使用了参数newNameValue。第⑤行是定义name属性的didSet观察者,oldNameValue是由我们分配的传递旧值的参数名,第⑥行是didSet观察者内部处理代码,其中使用了参数oldNameValue

第⑦行定义了Department类,第⑧行是定义no属性,第⑨行是定义no属性的willSet观察者,注意这里没有声明参数,但是我们可以在观察者内部使用newValue,见代码第⑩行,newValue是由系统分配的参数名。第⑪行是定义no属性的didSet观察者,注意这里也没有声明参数,但是我们可以在观察者内部使用oldValue,见代码第⑫行,oldValue是由系统分配的参数名。

上述代码运行结果如下:

  1. 员工name新值:Smith
  2. 员工name旧值:Tony
  3. 部门编号新值:30
  4. 部门编号旧值:10

对于这两个属性观察者,我们可以根据自己的需要来使用。它们常常应用于后台处理,以及需要更新界面的业务需求。