Swift Property Observers - didSet
概述
在 Swift 中,屬性觀察器(Property Observers)提供了一種監聽屬性值變化的機制。didSet 是其中一種觀察器,用於在屬性值被設定完成後執行特定的程式碼。
基本語法
var propertyName: Type = initialValue {
didSet {
// 屬性值改變後執行的程式碼
print("屬性已更新為: \(propertyName)")
}
}
willSet vs didSet
Swift 提供兩種屬性觀察器:
| 觀察器 | 執行時機 | 可存取的值 | 預設參數名稱 |
|---|---|---|---|
willSet | 屬性值即將改變前 | 新值 | newValue |
didSet | 屬性值改變後 | 舊值 | oldValue |
範例
var number: Int = 0 {
willSet {
print("即將把 number 從 \(number) 改成 \(newValue)")
}
didSet {
print("number 已從 \(oldValue) 改成 \(number)")
}
}
// 使用
number = 10
// 輸出:
// 即將把 number 從 0 改成 10
// number 已從 0 改成 10
實際應用場景
1. 基本用法
var score: Int = 0 {
didSet {
print("分數更新:\(oldValue) → \(score)")
// 可以觸發其他邏輯,如更新 UI、儲存到資料庫等
}
}
2. 與 @Published 的搭配使用
@Published var connectionState: ConnectionState = .initial {
didSet {
// 注意:@Published 已經自動處理 objectWillChange.send()
// 這裡的 didSet 通常用於額外的邏輯
if connectionState == .connected {
startHeartbeat()
}
}
}
3. 資料驗證與同步
var userName: String = "" {
didSet {
// 同步更新相關屬性
displayName = userName.isEmpty ? "匿名用戶" : userName
// 觸發 UI 更新
updateUserInterface()
}
}
重要注意事項
1. 與 @Published 的關係
@Published屬性包裝器已經自動處理了objectWillChange.send()- 在
@Published屬性上使用didSet時,通常不需要手動呼叫objectWillChange.send() didSet主要用於執行額外的業務邏輯
2. 避免無限遞迴
// ❌ 錯誤:可能造成無限遞迴
var value: Int = 0 {
didSet {
value = value + 1 // 這會再次觸發 didSet
}
}
// ✅ 正確:使用條件判斷
var value: Int = 0 {
didSet {
if value < 100 {
value = value + 1
}
}
}
3. 初始化時不會觸發
var count: Int = 10 { // 初始化時不會觸發 didSet
didSet {
print("count 改變 了")
}
}
最佳實踐
- 用途明確:
didSet主要用於執行副作用(side effects),如更新 UI、觸發通知等 - 避免複雜邏輯:保持
didSet內的程式碼簡潔,複雜邏輯應提取到獨立方法 - 效能考量:避免在
didSet中執行耗時操作 - 與 Combine 搭配:在 SwiftUI 中,優先考慮使用
@Published和 Combine 框架
總結
didSet 是 Swift 中強大的屬性觀察器,特別適合用於:
- 監聽屬性變化並執行相應邏輯
- 同步相關屬性的狀態
- 觸發 UI 更新或其他副作用
在 SwiftUI 開發中,與 @Published 搭配使用時,要注意避免重複的通知機制,並將 didSet 用於額外的業務邏輯處理。