编程iOS开发者

观察者属性在Swift中如何工作?它们有什么用?

用 Hintsage AI 助手通过面试

答案。

在Swift中,观察者属性允许对属性值的改变做出反应。这个概念伴随着Swift的出现,旨在提高对数据变化的控制透明度,并在变化时自动化逻辑。

问题背景:

在Swift之前,这种行为通常通过setter或特殊方法手动实现。在Swift中,观察者作为语言的标准工具出现。

问题:

开发者需要能够捕捉到属性值变化的时刻,例如,用于更新UI或验证数据。没有观察者,代码会变得更冗长且不易读取。

解决方案:

在Swift中,有两个主要的观察者可供使用:

  • willSet在值改变之前被调用
  • didSet在赋值后被调用

观察者可以添加到存储属性(stored property),但不能添加到延迟属性(lazy properties)和计算属性(computed properties)上。

代码示例:

class Temperature { var celsius: Double { willSet { print("即将设置值", newValue) } didSet { print("之前的值是:", oldValue, ", 现在是:", celsius) } } init(celsius: Double) { self.celsius = celsius } } let temp = Temperature(celsius: 22) temp.celsius = 28 // 会输出willSet和didSet

关键特点:

  • 在willSet中,可以访问特殊变量newValue
  • 在didSet中,可以访问oldValue
  • 在init中初始化属性时,观察者不会被调用

有陷阱的问题。

可以向计算属性添加观察者吗?

不可以,计算属性不能添加willSet和didSet,因为它们已经有自己的getter和setter。使用willSet/didSet仅适用于存储属性。

在初始化器内部更改属性时,观察者会被调用吗?

不会,属性观察者在初始化(init)期间不会被调用。它们只在init结束后更改值时被触发。

当将当前值赋值给自己,例如x = x时,会发生什么?

观察者仍然会被调用,即使属性值没有改变!这可能导致副作用,所以要小心。

var value: Int = 0 { didSet { print("didSet总是被调用!") } } value = value // didSet会被调用

常见错误和反模式

  • 依赖副作用:在didSet/willSet中实现业务逻辑会使代码不透明
  • 在"空"值改变中错误管理副作用,当值没有改变时
  • 将观察者用于计算属性而不是在setter中实现行为

生活中的例子

消极案例

开发者在didSet中实现了UI更新,但没有控制值的变化。在"空"赋值时,UI仍然会更新,导致性能下降。

优点:

  • 实现快速,代码少

缺点:

  • 不必要的操作增多,调试变得复杂

积极案例

在didSet中检查旧值和新值的相等性。只有在值确实改变时才更新UI。

优点:

  • 最小化副作用,性能高

缺点:

  • 需要额外的if检查,代码稍微多一些