Swift 4 KVO新语法observe使用问题求助
嘿,我看了你的代码,这里面有几个Swift 4 KVO常见的错误点,我帮你一一梳理:
1. 被观察的属性没满足KVO的必要条件
Swift 4对KVO的要求比之前严格,被观察的属性必须同时加上@objc和dynamic修饰符,而且所属的类必须继承自NSObject。你代码里的MyObjectToObserve和它的myDate属性得这么写才行:
class MyObjectToObserve: NSObject { @objc dynamic var myDate: Date init(date: Date) { self.myDate = date super.init() } }
要是没加这两个标记,KVO会悄无声息地失效,连编译报错都没有,这绝对是最容易踩的坑!
2. observe方法的调用对象错了
你现在是在MyObserver自己身上调用observe(\.objectToObserve.myDate),但我们要观察的是objectToObserve里的myDate变化,正确的做法应该是直接在objectToObserve这个目标对象上调用observe方法,修改后的代码应该是这样:
class MyObserver: NSObject { @objc var objectToObserve: MyObjectToObserve var observation: NSKeyValueObservation? init(object: MyObjectToObserve) { objectToObserve = object super.init() // 这里改成在objectToObserve上调用observe,观察它的myDate属性 observation = objectToObserve.observe(\.myDate) { [weak self] observedObj, change in // 用weak self避免循环引用,这也是内存管理的关键点 guard let self = self else { return } // 这里写你的处理逻辑,比如打印变化 print("日期更新了:\(observedObj.myDate)") } } }
原来的写法相当于观察MyObserver实例的objectToObserve.myDate路径,但objectToObserve本身如果不是dynamic属性,这个路径的KVO根本不会生效,逻辑上也完全不对。
3. 额外注意:内存管理与初始化顺序
初始化顺序这块你没问题,先给objectToObserve赋值再调用super.init()是正确的。不过要注意闭包的捕获,一定要加[weak self],不然MyObserver和objectToObserve会互相持有,导致内存泄漏。另外,NSKeyValueObservation只要你持有它,观察就会持续;一旦observation被释放,观察就自动停止,所以你把它存在MyObserver的属性里是正确的做法。
调整完这几点,你的KVO应该就能正常工作啦!
内容的提问来源于stack exchange,提问作者Eden

