屬性觀察器監聽並響應屬性值的變化。每次設置屬性值時都會調用,即使新值與舊值相同也不例外。適用於存儲屬性與繼承的計算屬性(需用 override 重寫)。
注意:對於自定義的計算屬性,直接在
setter中處理邏輯即可,無需額外添加觀察器。
| 方法 | 調用時機 | 參數 | 默認參數名 |
|---|---|---|---|
willSet | 設置新值之前 | 新值 | newValue |
didSet | 新值設置之後立即調用 | 舊值 | oldValue |
init 中賦值不會調用 willSet/didSet,只有初始化完成後、在其他地方設置值時才觸發。didSet 中再次賦值會替換原值:若在 didSet 內對屬性重新賦值,該新值將覆蓋剛設置的值(不會再次觸發觀察器,避免無限循環)。class Person: NSObject {
var age: Int? // 無觀察器
var name: String? { // 帶觀察器
willSet {
print("willSet: name 將從 \(name ?? \"nil\") 變為 \(newValue ?? \"nil\")")
}
didSet {
print("didSet: name 已從 \(oldValue ?? \"nil\") 變為 \(name ?? \"nil\")")
}
}
}
let p = Person()
p.name = "Alice" // 觸發 willSet -> didSet
p.name = "Bob" // 再次觸發
p.name = "Bob" // 值相同仍觸發
willSet: name 將從 nil 變為 Alice
didSet: name 已從 nil 變為 Alice
willSet: name 將從 Alice 變為 Bob
didSet: name 已從 Alice 變為 Bob
willSet: name 將從 Bob 變為 Bob
didSet: name 已從 Bob 變為 Bob
willSet 中攔截非法值,didSet 中格式化存儲。Swift 屬性觀察器提供了聲明式的屬性變化響應機制,willSet/didSet 配合 newValue/oldValue 參數,讓副作用邏輯與業務邏輯清晰分離。記住「初始化不觸發」與「didSet 可覆蓋值」兩大特性,避免常見坑點。