当我使用以下基于Swift 4基于闭包的KVO方式时,我在iOS 10设备上崩溃了
class A: NSObject {
@objc dynamic var value: Int = 0
var observation: NSKeyValueObservation?
override init() {
super.init()
// Crash
self.observation = self.observe(\A.value, options: [.new], changeHandler: { (_, change) in
})
}
}
var a: A? = A()
a = nil
崩溃信息:
***由于未捕获的异常'NSInternalInconsistencyException'终止了应用程序,原因:'类A的实例0x被释放,而键值观察器仍在其中注册。当前观察信息:(上下文:0x,属性:0x>
我用Google搜索,发现它是一个Swift错误:https://bugs.swift.org/browse/SR-5816,一种解决方法是在deinit
内添加以下几行
deinit {
if #available(iOS 11.0, *) {
} else {
if let observation = self.observation {
self.removeObserver(observation, forKeyPath: "value")
}
}
}
我的问题是
为什么下面的代码不会崩溃? (只需将观察者A更改为观察者B,它是A的成员)
class A: NSObject {
@objc dynamic var value: Int = 0
var observation: NSKeyValueObservation?
let b = B()
override init() {
super.init()
self.observation = self.b.observe(\B.value, options: [.new], changeHandler: { (_, change) in
})
}
}
class B: NSObject {
@objc dynamic var value: Int = 0
}
var a: A? = A()
a = nil
同时,如果我在上面的代码中添加了先前的解决方法,我将发生新的崩溃,为什么?
deinit {
if let observation = self.observation {
self.b.removeObserver(observation, forKeyPath: "value")
}
}
新的崩溃:
***由于未捕获的异常'NSRangeException'而终止应用程序,原因:'由于未将键路径“值”的观察者注册为观察者,因此无法将其移除。”