iOS 11. KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED 是什么意思? [英] iOS 11. What the KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED is mean?
问题描述
在新的 iOS11 中,我遇到了一些奇怪的异常.我不明白为什么会这样.在之前的iOS中,没有这样的例外.附上日志:
In the new iOS11, I get some strange exceptions. I do not understand why this is happening. In the previous iOS, there was no such exception. Log attached:
Crashed: com.apple.main-thread
0 libobjc.A.dylib 0x180a5e7e8 object_isClass + 16
1 Foundation 0x181f013e8 KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED + 68
2 Foundation 0x181eff8ec NSKeyValueWillChangeWithPerThreadPendingNotifications + 300
3 QuartzCore 0x18555a6dc CAAnimation_setter(CAAnimation*, unsigned int, _CAValueType, void const*) + 156
4 QuartzCore 0x18555d388 -[CAPropertyAnimation setKeyPath:] + 32
5 UIKit 0x18a9b1a08 -[UIImageView startAnimating] + 876
6 UIKit 0x18a9b0e78 -[UIActivityIndicatorView startAnimating] + 48
7 UIKit 0x18a9b0174 -[UIActivityIndicatorView _didMoveFromWindow:toWindow:] + 212
8 UIKit 0x18a95845c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 712
9 UIKit 0x18a95845c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 712
10 UIKit 0x18a95845c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 712
11 UIKit 0x18a95845c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 712
12 UIKit 0x18a95845c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 712
13 UIKit 0x18a95845c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 712
14 UIKit 0x18a95845c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 712
15 UIKit 0x18a95845c -[UIView(Internal) _didMoveFromWindow:toWindow:] + 712
16 UIKit 0x18a957918 __45-[UIView(Hierarchy) _postMovedFromSuperview:]_block_invoke + 156
17 Foundation 0x181e7c59c -[NSISEngine withBehaviors:performModifications:] + 168
18 UIKit 0x18a95778c -[UIView(Hierarchy) _postMovedFromSuperview:] + 824
19 UIKit 0x18a96339c -[UIView(Internal) _addSubview:positioned:relativeTo:] + 1728
20 UIKit 0x18abb3158 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke_2 + 1660
21 UIKit 0x18a969a84 +[UIView(Animation) performWithoutAnimation:] + 104
22 UIKit 0x18ab23864 __53-[_UINavigationParallaxTransition animateTransition:]_block_invoke + 264
23 UIKit 0x18ac418a4 +[UIView(Internal) _performBlockDelayingTriggeringResponderEvents:] + 220
24 UIKit 0x18ab2321c -[_UINavigationParallaxTransition animateTransition:] + 1112
25 UIKit 0x18aae1720 -[UINavigationController _startCustomTransition:] + 3444
26 UIKit 0x18aa02e04 -[UINavigationController _startDeferredTransitionIfNeeded:] + 712
27 UIKit 0x18aa02a34 -[UINavigationController __viewWillLayoutSubviews] + 124
28 UIKit 0x18aa0295c -[UILayoutContainerView layoutSubviews] + 188
29 UIKit 0x18a959000 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 1256
30 QuartzCore 0x1855290b4 -[CALayer layoutSublayers] + 184
31 QuartzCore 0x18552d194 CA::Layer::layout_if_needed(CA::Transaction*) + 332
32 QuartzCore 0x18549bf24 CA::Context::commit_transaction(CA::Transaction*) + 336
33 QuartzCore 0x1854c2340 CA::Transaction::commit() + 540
34 QuartzCore 0x1854c3180 CA::Transaction::observer_callback(__CFRunLoopObserver*, unsigned long, void*) + 92
35 CoreFoundation 0x1814f38b8 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 32
36 CoreFoundation 0x1814f1270 __CFRunLoopDoObservers + 412
37 CoreFoundation 0x1814f182c __CFRunLoopRun + 1292
38 CoreFoundation 0x1814122d8 CFRunLoopRunSpecific + 436
39 GraphicsServices 0x1832a3f84 GSEventRunModal + 100
40 UIKit 0x18a9bf880 UIApplicationMain + 208
谁遇到过这种情况?它是什么以及如何打败它?
Who ever encountered this? What is it and how to defeat it?
推荐答案
与KVO = Key-Value Observing有关.检查您是否正在调用该函数
It's related to KVO = Key-Value Observing. Check if you're calling the function
object.addObserver(self, forKeyPath:..., options:..., context:...)
某处;那是你的 KVO 观察者.这个类也会覆盖函数
somewhere; that's your KVO observer. This class would also override the function
observeValue(forKeyPath:of:change:context:)
正如错误消息所说,如果您在此处遇到崩溃,则意味着观察者被过度释放"或粉碎".我认为这只是意味着它在释放的同时仍在观察关键路径.
As the error message says, if you get a crash here, that means the observer was "overreleased" or "smashed". I think that just means it was released while still observing the key path.
如果您需要在 Swift 3 中修复它(就像我一样),请确保在您不再对观察关键路径感兴趣时调用 removeObserver
.最简单的方法是向观察者添加一个 deinit
方法:
If you need to fix it in Swift 3 (as I did), make sure you call removeObserver
once you are no longer interested in observing the key path. The easiest way to do that is to add a deinit
method to your observer:
deinit {
object.removeObserver(self, forKeyPath:#keyPath(same.as.in.addObserver))
}
确保将 object
和键路径替换为您在 addObserver
中使用的相同引用!
Make sure to replace object
and the key path with the same references you used in addObserver
!
更多信息:https://cocoacasts.com/key-value-observing-kvo-and-swift-3/
在 Swift 4/iOS 11 中,您可以使用块,如以下问题所示:In Swift 4, how do I remove a block-基于 KVO 的观察者?
From Swift 4 / iOS 11 you can use blocks, as in this question: In Swift 4, how do I remove a block-based KVO observer?
您可以像这样添加观察者,而不是使用 observeValue 方法:
Instead of using the observeValue method, you can just add the observer like so:
var observer: NSKeyValueObservation? = foo.observe(.value, options: [.new]) { (foo, change) in
print(change.newValue) // whatever needs to happen when the value changes
}
在 iOS 中,您仍应保留对观察者的引用并在适当的时间对其调用 invalidate
,例如在 deinit
或 viewWillDisappear
中.
In iOS, you should still keep a reference to the observer and call invalidate
on it at an appropriate time, e.g. in deinit
or in viewWillDisappear
.
如果您正在为 macOS 10.13 或更高版本进行开发,则在某些情况下不再需要将其删除.引用文档:
If you're developing for macOS 10.13 or newer, under certain conditions they no longer need to be removed. Quote from the docs:
宽松的键值观察注销要求
在 10.13 之前,如果在自动通知对象的 -dealloc 完成运行后仍有任何观察者注册,KVO 会抛出异常.此外,如果所有的观察者都被删除了,但在 dealloc 期间从另一个线程中删除了一些,那么仍然会错误地抛出异常.此要求已在 10.13 中放宽,但需满足两个条件:
Prior to 10.13, KVO would throw an exception if any observers were still registered after an autonotifying object's -dealloc finished running. Additionally, if all observers were removed, but some were removed from another thread during dealloc, the exception would incorrectly still be thrown. This requirement has been relaxed in 10.13, subject to two conditions:
- 对象必须使用 KVO 自动通知,而不是手动调用 -will 和 -didChangeValueForKey:(即它不应该从 +automaticallyNotifiesObserversForKey 返回 NO:)
- 对象不得覆盖内部 KVO 状态的(私有)访问器
如果所有这些都为真,则 -dealloc 返回后的任何剩余观察者都将被 KVO 清理;这也比重复调用 -removeObserver 方法更有效.
If all of these are true, any remaining observers after -dealloc returns will be cleaned up by KVO; this is also somewhat more efficient than repeatedly calling -removeObserver methods.
来源:https://developer.apple.com/library/archive/releasenotes/Foundation/RN-Foundation/index.html
这篇关于iOS 11. KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED 是什么意思?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!