KVO时iOS 11 AVPlayer崩溃

使用AVPlayer播放远程video时,我遇到了一个奇怪的崩溃。 从Fabric上的崩溃日志开始,应用程序在系统线程上崩溃( com.apple.avfoundation.playerlayer.configuration )。 崩溃日志如下:

Crashed: com.apple.avfoundation.playerlayer.configuration 0 libsystem_kernel.dylib 0x1839ac2e8 __pthread_kill + 8 1 libsystem_pthread.dylib 0x183ac12f8 pthread_kill$VARIANT$mp + 396 2 libsystem_c.dylib 0x18391afbc abort + 140 3 libsystem_malloc.dylib 0x1839e3ce4 szone_size + 634 4 QuartzCore 0x187ed75e8 -[CALayer dealloc] + 72 5 QuartzCore 0x187e75d90 CA::Transaction::commit() + 1052 6 AVFoundation 0x18973b4a8 -[AVPlayerLayer observeValueForKeyPath:ofObject:change:context:] + 684 7 Foundation 0x1847a2894 NSKeyValueNotifyObserver + 304 8 Foundation 0x1847bc364 -[NSObject(NSKeyValueObserverRegistration) _addObserver:forProperty:options:context:] + 204 9 Foundation 0x1847bc13c -[NSObject(NSKeyValueObserverRegistration) addObserver:forKeyPath:options:context:] + 124 10 AVFoundation 0x189760714 -[AVPlayer addObserver:forKeyPath:options:context:] + 204 11 AVFoundation 0x189890414 -[AVKVODispatcher startObservingValueAtKeyPath:ofObject:options:usingBlock:] + 136 12 AVFoundation 0x18989189c -[AVKVODispatcher(LegacyCallbackMethod) startObservingObject:weakObserver:forKeyPath:options:context:] + 152 13 AVFoundation 0x18973aef4 -[AVPlayerLayer _startObservingPlayer:] + 328 14 libdispatch.dylib 0x183816a54 _dispatch_call_block_and_release + 24 15 libdispatch.dylib 0x183816a14 _dispatch_client_callout + 16 16 libdispatch.dylib 0x18382096c _dispatch_queue_serial_drain$VARIANT$mp + 528 17 libdispatch.dylib 0x1838212fc _dispatch_queue_invoke$VARIANT$mp + 340 18 libdispatch.dylib 0x183821d20 _dispatch_root_queue_drain_deferred_wlh$VARIANT$mp + 404 19 libdispatch.dylib 0x18382a03c _dispatch_workloop_worker_thread$VARIANT$mp + 644 20 libsystem_pthread.dylib 0x183abef1c _pthread_wqthread + 932 21 libsystem_pthread.dylib 0x183abeb6c start_wqthread + 4 

注意:所有崩溃都发生在iOS11上

有没有人知道为什么会发生此次崩溃?

从堆栈跟踪中,我注意到AVPlayerLayer observeValueForKeyPath:ofObject:change:context:似乎是导致问题的原因。 因此,我相信你必须为AVPlayer实现KVO。

在这种情况下,请注意两点:

  1. 使用新的Key-Value-Observing iOS 11 API,您可以放宽要求 ,但不必从观察中取消注册的这些要求仅适用于以下条件:

轻松的键值观察注销要求

•对象必须使用KVO自动调整,而不是手动调用-will和-didChangeValueForKey :(即它不应该从+ automaticNotifiesObserversForKey :)返回NO。

•对象不得覆盖内部KVO状态的(私有)访问器。

请参阅此处 ,了解这是使用旧的API addObserverremoveObserver方法在新API中实现的。 请注意,文档对新API的帮助不大,因为它仍然基于旧的KVO实现。 但是,正如您所看到的,取消注册会在deinit自动发生。

AVFoundation隐藏了AVPlayer for KVO支持的实现(它是一个私有框架),但这些宽松的要求很可能不适用于AVPlayer 。 Apple于2018年发布的此代码片段使用AVPlayer和新的KVO API,但仍以deinit方式取消注册(确认怀疑AVPlayer不符合新API的轻松注销要求)。

另一种解释是取消注册发生在deinit ,但不一定在主线程中完成。 这对AVPlayer KVO很重要。

  1. 这很重要的原因可以从文档中找到:

一般状态观察:您应该在主线程上注册和注销KVO更改通知。 这避免了在另一个线程上进行更改时接收部分通知的可能性。

总之,如果使用新API为AVPlayer实现KVO,则需要在完成后显式取消注册。 另外,将您的注册和取消注册代码包装在DispatchQueue.main.async { }或类似的变体中。

我假设您的密钥路径有效(只需确保它们是动态属性)。