**KVO (Key-Value Observing) 核心使用的是觀察者模式**,而非「監聽者模式」(Listener Pattern)——兩者在 GoF 分類中本質相同,但 iOS 官方文檔、運行時源碼統一術語為 **Observer Pattern**。
// 觀察 "person.address.city"
[person addObserver:self forKeyPath:@"address.city" options:0 context:nil];
// 修改 city 時,Runtime 自動觸發 person 的 address.city 變更通知
// 依賴鍵由 +keyPathsForValuesAffecting 決定
系統維护一個全局映射:
`ObservedObject → (KeyPath → [ObserverInfo])`
`ObserverInfo` 包含:觀察者對象、選項、上下文指針、塊回調(iOS 13+ 支持 block 觀察)。
| 坑點 | 後果 | 規避 |
|---|---|---|
| 未移除觀察者就 dealloc | Crash:`NSInternalInconsistencyException` | deinit / dealloc 中 `removeObserver:forKeyPath:` |
| 重複添加同一觀察者 | 多次回調、移除困難 | 保持弱引用、統一管理註冊 |
| 觀察非 @objc / dynamic 屬性 | Swift 類屬性需加 @objc dynamic | Swift 類繼承 NSObject 或標記 @objc dynamic |
| 在 observeValueForKeyPath 中修改同屬性 | 無限遞歸、棧溢出 | 標記標誌位、異步處理或用 KVC 繞過 |
| 維度 | KVO | NotificationCenter | Combine |
|---|---|---|---|
| 耦合度 | 低(僅需 KeyPath 字符串) | 低(字符串名) | 極低(類型安全 Publisher) |
| 性能 | 中(Runtime 攔截 setter) | 高(異步分發) | 高(優化過的流式處理) |
| 適用場景 | 屬性級別變更監聽 | 跨模塊事件廣播 | 現代響應式編程、異步鏈 |
| 線程安全 | 同線程同步回調 | 可指定隊列 | 可指定調度器 |
「KVO 底層通過 **ISA 混寫** 動態生成中間類重寫 setter,在 `willChangeValueForKey:` / `didChangeValueForKey:` 包裹原始賦值,實現屬性變更的自動感知。這是 **觀察者模式** 在 Runtime 層的極致體現。相比 NotificationCenter,KVO 更適合**細粒度屬性綁定**;但現代 Swift 開發首選 **Combine** 或 **Swift Observation (iOS 17+)**,獲得編譯期類型安全與結構化並發支持。」
KVO 使用**觀察者模式**,核心技術是 **ISA 混寫 + setter 攔截 + 依賴鍵路徑**。面試時說清「動態生成中間類、修改 isa、重寫 setter、分發通知」四步走,再對比 Combine/NotificationCenter,即可展示對 iOS 運行時機制的深度理解。