iOS 11. KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED 这是什么意思?

34

在新的iOS11版本中,我遇到了一些奇怪的异常。我不明白为什么会出现这种情况,在之前的iOS版本中没有出现这个异常。附上日志:

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

谁曾经遇到过这个问题?它是什么,如何击败它?

1个回答

45

这与KVO(键值观察)有关。请检查您是否调用了该函数。

object.addObserver(self, forKeyPath:..., options:..., context:...)

在某个地方,那就是你的KVO观察者。这个类还将重写该函数。

observeValue(forKeyPath:of:change:context:)

作为错误信息所述,如果在此处发生崩溃,这意味着观察者已经"被释放过度"或者"被损坏"。我认为这只是意味着它在仍在观察键路径时就被释放了。
如何解决?
Swift 3
如果您需要在Swift 3中修复它(就像我一样),请确保在您不再对键路径进行观察时调用removeObserver。最简单的方法是向观察者中添加一个deinit方法。
deinit {
    object.removeObserver(self, forKeyPath:#keyPath(same.as.in.addObserver))
}

请确保将object和键路径替换为您在addObserver中使用的相同引用!

更多信息:https://cocoacasts.com/key-value-observing-kvo-and-swift-3/

Swift 4 / iOS

从Swift 4 / iOS 11开始,您可以使用块,就像这个问题中所示:In Swift 4,如何删除基于块的KVO观察者?

您可以像这样添加观察者,而无需使用observeValue方法:

var observer: NSKeyValueObservation? = foo.observe(.value, options: [.new]) { (foo, change) in
   print(change.newValue)     // whatever needs to happen when the value changes
}

在iOS中,您仍应保留对观察者的引用,并在适当的时间调用invalidate,例如在deinitviewWillDisappear中。如果您正在开发适用于macOS 10.13或更高版本的应用程序,则在某些条件下,它们不再需要被移除。引用文档中的话:“放松键-值观察注销要求。在10.13之前,如果自动通知对象的-dealloc完成运行后仍然注册了任何观察者,KVO会抛出异常。此外,如果所有观察者都被删除,但是在dealloc期间从另一个线程中删除了一些观察者,则错误地仍然会抛出异常。在10.13中,这个要求已经放松了,但有两个条件:对象必须使用KVO自动通知,而不是手动调用-will和-didChangeValueForKey:(即它不应该从+automaticallyNotifiesObserversForKey:返回NO),对象不能覆盖内部KVO状态的(私有)访问器。如果所有这些条件都成立,则在-dealloc返回后仍然存在的任何剩余观察者将被KVO清除;这也比重复调用-removeObserver方法要更有效率。”来源:https://developer.apple.com/library/archive/releasenotes/Foundation/RN-Foundation/index.html

嘿,我也遇到了同样的问题!我正在为此删除观察者。但它仍然崩溃。
  • (void)dealloc { [self.xmppManager removeObserver:self forKeyPath:@"isGroupConnected"]; [self.notificationCenter removeObserver:self]; _fetchedResultsController.delegate = nil; }
- Ashwin Sathawane
2
不幸的是,我在使用基于块的观察器来观察“Progress”对象的“fractionCompleted”属性时遇到了崩溃。唉...基于块的观察 - 它可以正常工作,除非它不能。 - Jon Brooks
1
警告:我不会做文档中说不要做的事情。在这种情况下,我会注销所有观察者。你提供的答案并不支持文档中所说的“现在不再有惩罚...”。请参见:(文档)[https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html] - Pranav Kasetti
3
使用Xcode 10ß6和Swift 4,我可以明确确认无效化观察令牌(针对基于块的观察)可以解决面向iOS 12的应用程序的问题。 - Constantino Tsarouhas
我在GSMMapView内部函数上遇到了同样的崩溃,请看一下。https://stackoverflow.com/questions/54129679/random-kvo-block-crashes-when-allocating-mapview-happens-only-when-open-close-s - Ali AKhtar
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接