最近一直在做视频的东西,记录下开发过程中遇到的坑和解决办法。
我们关于视频播放的模块有下载下来观看和线上观看两种,开始我是直接建了一个视频播放的view,这两种都用了这个view。以下是视频播放的简单记录:
#import <AVFoundation/AVFoundation.h>
#import <AVKit/AVKit.h>
#import <MediaPlayer/MediaPlayer.h>
/**
<#Description#>
@return <#return value description#>
*/
- (AVPlayer *)player {
if (!_player) {
_player = [AVPlayer playerWithPlayerItem:[AVPlayerItem playerItemWithURL:[NSURL URLWithString:@""]]];
if ([[UIDevice currentDevice] systemVersion].intValue >= 10) {
if (@available(iOS 10.0, *)) {
_player.automaticallyWaitsToMinimizeStalling = NO;
} else {
// Fallback on earlier versions
}
}
}
return _player;
}
[self.playerItem removeObserver:self forKeyPath:@"status"]; [self.playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
[self.playerItem removeObserver:self forKeyPath:@"playbackBufferEmpty"];
[self.playerItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
self.playerItem = nil;
self.playerItem = [AVPlayerItem playerItemWithURL:url];
[self.player replaceCurrentItemWithPlayerItem:self.playerItem];
self.player.volume = 1.0;
[self.player play];
// 监控状态属性,注意AVPlayer也有一个status属性,通过监控它的status也可以获得播放状态
[self.playerItem addObserver:self forKeyPath:kVideoPlayerItemStatus options:NSKeyValueObservingOptionNew context:nil];
//监控网络加载情况属性
[self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
// Will warn you when your buffer is empty
[self.playerItem addObserver:self forKeyPath:@"playbackBufferEmpty" options:NSKeyValueObservingOptionNew context:nil];
// Will warn you when your buffer is good to go again.
[self.playerItem addObserver:self forKeyPath:@"playbackLikelyToKeepUp" options:NSKeyValueObservingOptionNew context:nil];
功能做好后发现线上播放的时候关闭viewcontroller后视频播放的view没有走dealloc方法,其实ARC里不用太在意dealloc方法,但是如果有通知的话还是最好在这个方法里移除,我这个view里就有通知(做过视频播放的应该都知道需要实现监听系统通知)。
经过一番打断点后发现下载下来看的走了dealloc,而在线看的没有走,于是我就开始各种尝试,终于发现是给AVplayeritem添加KVO监听status导致的问题,但是这个又是必须监听的,于是查找dealloc方法为什么不调用(此处不深究),原因竟然是我的block里用的_全局变量而不是self.调用 ,代码规范一定不能忽视,不然会出现很多让你没有头绪的bug。
走了dealloc方法以为就ok了,但是走完就崩了,设置了全局断点却依然崩在了main函数里,哭晕。
几次毫无意义调试后意识到可能要开启僵尸模式(edit scheme中diagnotics的memory management勾选zombie object)。果然开启后给了崩溃原因[(视频播放view)class retain]: message sent to deallocated instance 0x11371b9e0 一番百度后说是过度释放导致的,但是viewcontroller中的dealloc中显示这个view的引用计数是2,只能想想别的办法,仔细看了代码后怀疑是这个view的hidden属性问题,于是我就改成了alpha,改完后在我iOS11.3的系统上还真不闪退了,窃喜。开心过后想到测试机8.3的系统不知道运行有没有问题,试了后果然又崩了,内心是崩溃的。。。
iOS8.3崩溃还连崩溃原因都不给了,真的是给Xcode跪了,苦思冥想后决定把全局断点去掉看看效果,去掉后果然给了崩溃原因
An instance of class AVPlayerItem was deallocated while key value observers were still 。。。
这个好像说的是kvo没有移除的原因,然后果断在dealloc里移除了kvo,然后又把alpha改为了hidden,毕竟alpha更耗性能。
至此终于解决了这个困扰好几天的问题。