iOS 11. KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_

Posted

技术标签:

【中文标题】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?iOS 11. KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_SMASHED 是什么意思? 【发布时间】:2018-03-28 16:28:25 【问题描述】:

在新的 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】:

与KVO = Key-Value Observing有关。检查您是否正在调用该函数

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

某处;那是你的 KVO 观察者。这个类也会覆盖函数

observeValue(forKeyPath:of:change:context:)

正如错误消息所说,如果您在此处遇到崩溃,则意味着观察者被“过度释放”或“粉碎”。我认为这只是意味着它在释放的同时仍在观察关键路径。

如何解决?

斯威夫特 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/

斯威夫特 4 / iOS

从 Swift 4 / iOS 11 开始,您可以使用块,如以下问题:In Swift 4, how do I remove a block-based KVO observer?

您可以像这样添加观察者,而不是使用 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

Swift 4 / macOS

如果您正在为 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; 错误信息是什么?如果您不小心多次调用 [removeObserver: forKeyPath:],它也会崩溃。我现在要做的是使用一个额外的 Bool 变量,例如“observingKeyPath”并在我调用 addObserver 时将其设置为 true。然后当我完成后,只有当observingKeyPath 为真时,我才调用removeObserver 并将observingKeyPath 设置为假。 不幸的是,我在 Progress 对象的 fractionCompleted 属性上使用基于块的观察者遇到了这个崩溃。叹息......基于块的观察 - 它只是有效,除非它没有。 警告:我不会做文档上说不应该做的事情。在这种情况下,我会注销所有观察者。当您链接到的答案说“不再有惩罚......”时,它不支持文档。请参阅:(文档)[developer.apple.com/library/content/documentation/Cocoa/… 使用 Xcode 10 ß6 和 Swift 4,我可以确认明确地使观察令牌无效(用于基于块的观察)解决了针对 iOS 12 的应用程序的问题。

以上是关于iOS 11. KVO_IS_RETAINING_ALL_OBSERVERS_OF_THIS_OBJECT_IF_IT_CRASHES_AN_OBSERVER_WAS_OVERRELEASED_OR_的主要内容,如果未能解决你的问题,请参考以下文章

_IO_FILE 的 Pybind11 文件指针包装器

javascript redllama_iOS_11.js

Python_Day11_同步IO和异步IO

JavaSE复习_11 IO流复习

从 iOS 11+ 项目中删除 SceneDelegate 的正确方法 - 应用程序中需要哪些代码(_:didFinishLaunchingWithOptions)

设置 UIBarButtonItem 动画在 iOS 11 上不起作用