隨著 keypath 得到增強,KVC 和 KVO 的 API 都有了一些進化。
struct 也支援 KVC
一個感人的進步就是 struct 也支援 KVC 了。但是並不是使用原有的setValue:forKeypath
的api。而是利用了swfit 4增加的一個語法特性:自定義索引可以有引數名。
直接上程式碼吧:
struct ValueType {
var name:String
}
var object = ValueType(name: "zhuo")
let name = \ValueType.name
// set
object[keyPath: name] = "swift4"
// get
let valueOfName = object[keyPath:name]複製程式碼
通過索引可以方便的進行KVC。
KVO
遺憾的是依然只有 NSObject 才能支援 KVO。
Swift 4中的一個對此有影響的改變是繼承 NSObject 的 swift class 不再預設全部 bridge 到 OC。原因可以參考我的前一篇部落格:Swift 4新知:自動清除冗餘程式碼減小包大小。然而 KVO 又是一個純 OC 的特性,所以如果是 swift class 需要在宣告的時候增加 @objcMembers
關鍵字。否則在執行的時候你會得到一個 error:
fatal error: Could not extract a String from KeyPath Swift.ReferenceWritableKeyPath
另外一件事就是被觀察的屬性需要用dynamic
修飾,否則也無法觀察到。
一個好訊息是不需要在物件被回收時手動 remove observer。但是這也帶來了另外一個容易被忽略的事情:觀察的閉包沒有被強引用,需要我們自己新增引用,否則當前函式離開後這個觀察閉包就會被回收了。
@objcMembers class OCClass: NSObject {
dynamic var name: String
init(name: String) {
self.name = name
}
}
class ViewController: UIViewController {
var swiftClass: OCClass!
var ob: NSKeyValueObservation!
override func viewDidLoad() {
super.viewDidLoad()
swiftClass = OCClass(name: "oc")
ob = swiftClass.observe(\.name) { (ob, changed) in
let new = ob.name
print(new)
}
swiftClass.name = "swift4"
}
}複製程式碼
KVO 之後返回的是一個 NSKeyValueObservation
例項,需要自己控制這個例項的生命週期。
參考:
Key Value Observation in iOS 11
smart key path
Re-enabling @objc inference within a class hierarchy
歡迎關注我的微博:@沒故事的卓同學