Skip to main content

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 改變了")
}
}

最佳實踐

  1. 用途明確didSet 主要用於執行副作用(side effects),如更新 UI、觸發通知等
  2. 避免複雜邏輯:保持 didSet 內的程式碼簡潔,複雜邏輯應提取到獨立方法
  3. 效能考量:避免在 didSet 中執行耗時操作
  4. 與 Combine 搭配:在 SwiftUI 中,優先考慮使用 @Published 和 Combine 框架

總結

didSet 是 Swift 中強大的屬性觀察器,特別適合用於:

  • 監聽屬性變化並執行相應邏輯
  • 同步相關屬性的狀態
  • 觸發 UI 更新或其他副作用

在 SwiftUI 開發中,與 @Published 搭配使用時,要注意避免重複的通知機制,並將 didSet 用於額外的業務邏輯處理。