Swift 中可以使用鍵值觀察 (KVO) 嗎?


在 Swift 中,您可以使用 KVO 透過為該屬性註冊觀察者來觀察物件屬性的更改。當屬性值更改時,會通知觀察者,並可以採取適當的操作。在本文中,您將看到如何在 Swift 中實現 KVO 的示例。

要在 Swift 中使用 KVO,您需要執行以下操作

  • 使用 @objc dynamic 屬性標記要觀察的屬性。此屬性告訴 Swift 編譯器為該屬性生成與 Objective-C 相容的程式碼。

  • 使用被觀察物件的 addObserver(_:forKeyPath:options:context:) 方法註冊該屬性的觀察者。

  • 在觀察者中實現 observeValue(forKeyPath:of:change:context:) 方法以處理對被觀察屬性的更改。

addObserver(_:forKeyPath:options:context:) 方法

addObserver(_:forKeyPath:options:context:) 方法用於為物件的特定鍵路徑新增觀察者。它採用以下引數:

  • observer - 觀察鍵路徑的物件。

  • keyPath - 指定要觀察的鍵路徑的字串。

  • options - 確定如何向觀察者報告鍵路徑更改的選項陣列。

  • context - 當通知觀察者更改時傳遞給觀察者的上下文物件。

options 引數是一個選項陣列,用於確定如何將對被觀察鍵路徑的更改報告給觀察者。可用的選項包括:

  • .old - 在報告更改時,在更改字典中包含屬性的舊值。

  • .new - 在報告更改時,在更改字典中包含屬性的新值。

  • .initial - 在新增觀察者時報告屬性的初始值。

  • .prior - 在報告更改時,在更改字典中包含屬性的上一個值。

context 引數是任意上下文物件,當通知觀察者更改時傳遞給觀察者。這可用於向觀察者提供其他資訊。

removeObserver(_:forKeyPath:) 方法

removeObserver(_:forKeyPath:) 方法用於刪除物件的特定鍵路徑的觀察者。它採用以下引數:

  • observer - 觀察鍵路徑的物件。

  • keyPath - 指定停止觀察的鍵路徑的字串。

當不再需要觀察者時,必須將其移除。這是為了避免記憶體洩漏並防止觀察者在其被釋放後接收通知。

@objc dynamic

@objc dynamic 是 Swift 語言屬性,用於使類的屬性在 Objective-C 中可以透過鍵值觀察 (KVO) 進行觀察。KVO 是一種允許物件觀察另一個物件屬性的更改的機制。

@objc 屬性用於將 Swift 類或其成員公開給 Objective-C,以便 Objective-C 程式碼可以使用它們。dynamic 屬性用於告訴編譯器對屬性或方法使用動態排程而不是靜態排程。這意味著屬性或方法可以在執行時被重寫。

為了使屬性可以透過 KVO 進行觀察,它必須同時使用 @objc 和 dynamic 進行標記。當屬性使用 @objc dynamic 標記時,編譯器會生成其他程式碼,從而為該屬性啟用 KVO。這包括建立一個新的動態子類,該子類重寫屬性的 getter 和 setter 方法,以便在屬性值更改時通知註冊的觀察者。

示例

import Foundation
class Person: NSObject {
   // Declare the property that you want to observe as @objc dynamic in the class where it is defined.
   @objc dynamic var name: String = ""
}
// Define a new observer class that inherits from NSObject.
class PersonObserver: NSObject {
   var person: Person
   init(person: Person) {
      self.person = person
      super.init()
      person.addObserver(self, forKeyPath: #keyPath(Person.name), options: [.old, .new], context: nil)
   }
   deinit {
      person.removeObserver(self, forKeyPath: #keyPath(Person.name))
   }
   override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
      guard keyPath == #keyPath(Person.name),
      let newValue = change?[.newKey] as? String,
      let oldValue = change?[.oldKey] as? String else {
         return
      }
      print("Property '\(keyPath!)' changed from '\(oldValue)' to '\(newValue)'")
   }
}
// Create an instance of Person and an instance of PersonObserver.
let alex = Person()
let observer = PersonObserver(person: alex)
// Change the value of the name on alex
alex.name = "Alex"
alex.name = "Alex Murphy"

輸出

Property 'name' changed from '' to 'Alex'
Property 'name' changed from 'Alex' to 'Alex Murphy'

在此示例中,Person 是被觀察的物件,PersonObserver 是觀察者。Person 的 name 屬性使用 @objc dynamic 屬性進行標記以啟用 KVO。觀察者為 alex 的 name 屬性註冊,並實現 observeValue(forKeyPath:of:change:context:) 方法以處理對該屬性的更改。當屬性值更改時,會呼叫觀察者的方法實現,並傳入更改後的值。

結論

總之,@objc dynamic 是 Swift 語言屬性,用於使類的屬性在 Objective-C 中可以透過鍵值觀察 (KVO) 進行觀察。為了使屬性可以透過 KVO 進行觀察,必須同時使用 @objc 和 dynamic 進行標記。當屬性使用 @objc dynamic 標記時,編譯器會生成其他程式碼,從而為該屬性啟用 KVO。建議僅在屬性需要在 Objective-C 中透過 KVO 進行觀察時才使用 @objc dynamic,因為不必要地使用它可能會影響效能。

更新於:2023年5月4日

1K+ 次檢視

啟動你的職業生涯

完成課程獲得認證

開始學習
廣告
© . All rights reserved.