iOS 11 AVPlayer 在 KVO 时崩溃
iOS 11 AVPlayer crash when KVO
我在使用 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
有人知道为什么会发生此崩溃吗?
从您的堆栈跟踪中,我注意到 AVPlayerLayer observeValueForKeyPath:ofObject:change:context:
似乎是导致您出现问题的原因。因此,我相信您必须为 AVPlayer
.
实施 KVO
在这种情况下,注意两点:
- 使用新的 Key-Value-Observing iOS 11 API 你有 relaxed requirements,但是这些不必从观察中注销的要求仅适用于以下条件:
Relaxed Key-Value Observing Unregistration Requirements
• The object must be using KVO autonotifying, rather than manually
calling -will and -didChangeValueForKey: (i.e. it should not return NO
from +automaticallyNotifiesObserversForKey:).
• The object must not
override the (private) accessors for internal KVO state.
请参阅 here 以了解在新 API 中使用旧 API addObserver
和 removeObserver
方法实现的这一点。请注意,该文档目前对新的 API 不是很有帮助,因为它仍然基于旧的 KVO 实现。但是,如您所见,取消注册会在 deinit
.
自动发生
AVFoundation
隐藏了 AVPlayer
对 KVO 支持的实现(这是一个私有框架),但这些宽松的要求很可能不适用于 AVPlayer
。 This Apple 在 2018 年的代码片段,使用 AVPlayer
和新的 KVO API,但仍然以 deinit
方法注销(证实 AVPlayer
没有满足新 API).
的宽松注销要求
另一种解释是注销发生在deinit
,但不一定在主线程中完成。这对 AVPlayer
KVO 很重要。
- 这很重要的原因可以从 docs:
中找到
General State Observations: You should register and unregister for KVO change notifications on the
main thread. This avoids the possibility of receiving a partial
notification if a change is being made on another thread.
总而言之,如果使用新的 API 为 AVPlayer
实施 KVO,您需要在完成后显式 注销。此外,将您的注册和注销代码包装在 DispatchQueue.main.async { }
或类似变体中。
我在这里假设你的关键路径是有效的(只要确保它们是动态属性)。
我在使用 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
有人知道为什么会发生此崩溃吗?
从您的堆栈跟踪中,我注意到 AVPlayerLayer observeValueForKeyPath:ofObject:change:context:
似乎是导致您出现问题的原因。因此,我相信您必须为 AVPlayer
.
在这种情况下,注意两点:
- 使用新的 Key-Value-Observing iOS 11 API 你有 relaxed requirements,但是这些不必从观察中注销的要求仅适用于以下条件:
Relaxed Key-Value Observing Unregistration Requirements
• The object must be using KVO autonotifying, rather than manually calling -will and -didChangeValueForKey: (i.e. it should not return NO from +automaticallyNotifiesObserversForKey:).
• The object must not override the (private) accessors for internal KVO state.
请参阅 here 以了解在新 API 中使用旧 API addObserver
和 removeObserver
方法实现的这一点。请注意,该文档目前对新的 API 不是很有帮助,因为它仍然基于旧的 KVO 实现。但是,如您所见,取消注册会在 deinit
.
AVFoundation
隐藏了 AVPlayer
对 KVO 支持的实现(这是一个私有框架),但这些宽松的要求很可能不适用于 AVPlayer
。 This Apple 在 2018 年的代码片段,使用 AVPlayer
和新的 KVO API,但仍然以 deinit
方法注销(证实 AVPlayer
没有满足新 API).
另一种解释是注销发生在deinit
,但不一定在主线程中完成。这对 AVPlayer
KVO 很重要。
- 这很重要的原因可以从 docs: 中找到
General State Observations: You should register and unregister for KVO change notifications on the main thread. This avoids the possibility of receiving a partial notification if a change is being made on another thread.
总而言之,如果使用新的 API 为 AVPlayer
实施 KVO,您需要在完成后显式 注销。此外,将您的注册和注销代码包装在 DispatchQueue.main.async { }
或类似变体中。
我在这里假设你的关键路径是有效的(只要确保它们是动态属性)。