AVPlayer.currentItemをiOS8で取り扱うときの注意
....。
このご時世にこれだけ iOS 8 のこと書いてるのって僕だけじゃない?(笑)
ってことで、
AVPlayer.currentItem
をKVOで監視してるとやばい...!!
です
環境
- Xcode v9.3.1
問題
webにあがってる動画を読み込んで流すということをしている時に、
動画のサイズ(width x height)が欲しくって
それを実現するのにAVPlayerItem
の status を監視することで実現しようとしたのです。
let player = AVPlayer(url: URL(string: "動画URL")!)
self.observation = player.currentItem?.observe(\.status, changeHandler: { (item, _) in
switch item.status {
case .readyToPlay:
print(item.presentationSize)
default: break
}
})
こういう感じですね。
これでやりたかったことはできるのですけれど、
とある条件下でクラッシュします。
クラッシュする条件
以下の2つです。
- iOS 8 端末であること
- 動画URLが読み込めない(リンク切れなど)
どうやら、iOS 8 の場合読み込めないと、AVPlayer
が内部でAVPlayerItem
を解放するようなのです。
で、上記の例だとKVOでplayer.currentItem
の status を監視しているわけですから...クラッシュするというわけです
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x7867a000 of class AVPlayerItem was deallocated while key value observers were still registered with it.
解放するまえに status の監視を解除しろっていうことですね..。
ちなみにこういう感じで nil になるのをチェックしました
let player = AVPlayer(url: URL(string: "なにかリンク切れの動画リンク")!)
observation = player.observe(\.currentItem) { (player, changedValue) in
print(player.currentItem == nil)
}
iOS 8 の場合は、trueとログが吐かれるのです。
対策
対策は簡単で、AVplayerItem
のインスタンスもちゃんと自分でも参照を持つというとこですね。
self.playerItem = AVPlayerItem(url: URL(string: "なにかリンク切れのリンク")!)
let player = AVPlayer(playerItem: self.playerItem)
こういう感じで。
これで、AVPlayer
が読み込めなかった時に破棄しようとしても、自分が参照もってるから防げるというわけです。
(もちろん適宜KVOは解除ひつようですよ!)
いやーー自分で持つのめんどくせ...Playerは持ってるからそいつでみたらいいでしょ!
って怠けちゃったばっかりにこういうことになりますよっと....
(どこのサンプルでも大抵はAVPlayerItem
をちゃんと持つようになってるから、多くの人は大丈夫なはず....😇)
変な方向で怠けるとだいたい後ろから襲われますね...