当KVO

时间:2018-02-04 10:42:38

标签: ios objective-c swift avfoundation avplayer

使用 AVPlayer 播放远程视频时,我遇到了一个奇怪的崩溃。从 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

有人知道发生此次崩溃的原因吗?

1 个答案:

答案 0 :(得分:5)

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

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

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

    放宽键值观察注销要求

         

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

         

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

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

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

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

    1. 这一点很重要的原因可以从docs
    2. 找到
        

      一般状态观察:您应该注册并取消注册KVO更改通知   主线程。这避免了接收部分的可能性   如果正在对另一个线程进行更改,则会发出通知。

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

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