我最近开始使用 iOS 11 作为目标版本开发我的应用程序,因为这是默认值。由于某些原因,我现在已经将版本降低到 9.3。
该应用程序是纯 Swift 4,使用新的 KVO block 。
我修复了我在 safeAreaInsets 等方面遇到的一些编译时错误,并成功构建了应用程序。一个快速的工作。不错。
我尝试在 iPhone 7 iOS 10.3.1 模拟器上运行它,老天爷——这是一场火车事故。我想 UITableViewAutomaticDimension 在过去并不是真正的东西。
无论如何,我已经修复了大部分布局问题,但现在我遇到了一些严重的崩溃问题。无论我在哪里使用这个新的 KVO,当我返回时它都会崩溃。 我的导航推送 ViewController 是 KVO 监听它所持有的对象内的字段。当我弹出导航时,viewController 和对象按顺序被释放,应用程序崩溃,给我这个错误:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x7fdf2e724250 of class MyProject.MyObject was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x60800003fd80> (
<NSKeyValueObservance 0x610000050020: Observer: 0x61000006f140, Key path: isSelected, Options: <New: NO, Old: NO, Prior: NO> Context: 0x0, Property: 0x6180000595f0>
)'
据我所知,它说当有人观察变量 isSelected 时,观察到的对象 MyObject 被释放。
这是观察 MyObject 的 MyViewController 中的观察代码。
var observations:[NSKeyValueObservation] = []
func someFunction() {
observations.removeAll()
let myObject = MyObject(/*init*/)
self.myObject = myObject
observations.append(myObject.observe(\.isSelected, changeHandler: { [weak self] (object, value) in
//Do stuff
}))
}
我的印象是这种新的神奇 KVO block 样式会解决世界和平,但显然这只适用于 iOS 11。
现在,我已经尝试了一些东西,但我无法让它不崩溃。每次都这样,我不明白为什么。
因为崩溃日志告诉我被观察对象正在被释放,而一个对象正在观察它,但我也知道观察对象在被观察对象之前被释放,我已经尝试在观察者中这样做:
//In MyViewController
deinit {
observations.forEach({$0.invalidate()})
observations.removeAll()
print("Observers removed")
}
但这并没有帮助。我也这样做过:
//In MyObject
deinit{
print("MyObject deinit")
}
当我这样做时 - 我得到以下输出:
>Observers removed
>MyObject deinit
>WORLD WAR 5 STACK TRACE
我也试过
//In MyViewController
deinit{
self.myObject.removeObserver(self, forKeyPath: "isSelected")
}
但是我得到的输出是 Can't remove because it is not registered as an observer。所以我猜 MyViewController 不是实际上在使用这个新的 KVO 时附加的观察者。
为什么这些都不起作用?在 < ios11="">
最佳答案
看起来你遇到了我大约一年前报告的错误,但不幸的是,它很少受到关注:
https://bugs.swift.org/browse/SR-5752
因为这个错误已经有一段时间没有困扰我了,我曾希望它已经在 Swift 覆盖中得到修复,但我只是尝试将我的代码从错误报告复制到一个 iOS 项目中并在 10.3 中运行它.1 模拟器,果然,崩溃又回来了。
你可以像这样解决它:
deinit {
for eachObservation in observations {
if #available(/*whichever version of iOS fixes this*/) { /* do nothing */ } else {
self.removeObserver(eachObservation, forKeyPath: #keyPath(/*the key path*/))
}
eachObservation.invalidate()
}
observations.removeAll()
}
请确保您只在受错误影响的 iOS 版本上执行此操作,否则您将删除已经删除的观察结果,然后那个可能会崩溃。这不是很有趣吗?
关于ios - Swift 4 KVO block 崩溃 : observed object deallocated while observer was still registered,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50052347/