アプリでランダムなクラッシュ(所有しているデバイスでは再現できません)が発生しますが、例外があります。
オブザーバーとして登録されていないため、AVPlayerLayer 0xaddressからキーパス「readyForDisplay」のオブザーバーFoundation.NSKeyValueObservation 0xaddressを削除できません。
これは、AVPlayerLayerを含むUIViewの割り当てを解除すると発生します。
私のinit:
private var playerLayer : AVPlayerLayer { return self.layer as! AVPlayerLayer }
init(withURL url : URL) {
...
self.asset = AVURLAsset(url: url)
self.playerItem = AVPlayerItem(asset: self.asset)
self.avPlayer = AVPlayer(playerItem: self.playerItem)
super.init(frame: .zero)
...
let avPlayerLayerIsReadyForDisplayObs = self.playerLayer.observe(\AVPlayerLayer.isReadyForDisplay, options: [.new]) { [weak self] (plLayer, change) in ... }
self.kvoPlayerObservers = [..., avPlayerLayerIsReadyForDisplayObs, ...]
...
}
例外がスローされる私のdeinit:
deinit {
self.kvoPlayerObservers.forEach { $0.invalidate() }
...
NotificationCenter.default.removeObserver(self)
}
Crashlyticsによると、それはさまざまなiPhoneのiOS 11.4.1で発生します。
deinit
につながるコードはかなり単純です:
// Some UIViewController context.
self.viewWithAVLayer?.removeFromSuperview()
self.viewWithAVLayer = nil
これがなぜ起こるかについての私はどんな考えにも感謝します。
私は このバグ を見ましたが、それは私にとって原因ではないようです。
編集1:
後世のための追加情報。 iOS 10では、無効化しないと、deinitで再現可能なクラッシュが発生します。 iOS 11では無効化なしで動作します(無効化せずにオブザーバーにクラスをdeinit
edさせるとクラッシュが消えてもまだチェックされません)。
編集2:
後世のための追加情報:私はこれも発見しましたSwift関連する可能性のあるバグ- SR-6795 。
後
self.kvoPlayerObservers.forEach { $0.invalidate() }
追加
self.kvoPlayerObservers.removeAll()
また、この行は好きではありません。
self.kvoPlayerObservers = [..., avPlayerLayerIsReadyForDisplayObs, ...]
kvoPlayerObservers
はセットであり、オブザーバーを受け取ったら1つずつ挿入する必要があります。
mattの回答は受け入れましたが、実際に問題にどのように取り組んだかについての詳細を提供したいと思います。
クラッシュしない私のdeinitは次のようになります。
_if let exception = tryBlock({ // tryBlock is Obj-C exception catcher.
self.kvoPlayerObservers.forEach { $0.invalidate() };
self.kvoPlayerObservers.removeAll()
}) {
remoteLoggingSolution.write(exception.description)
}
... // do other unrelated stuff
_
基本的に、発生した場合にObj-C例外をキャッチして、リモートでログに記録しようとします。
私はこのコードを過去2週間運用していて、それ以来、クラッシュも例外ログも受信しなかったので、mattがkvoPlayerObservers.removeAll()
を追加するという提案は正しい(少なくとも私の特定のケースでは)。