问题原因:
在APP制作时有一个需求是要在一个tableview里存在多个MPMoviePlayerController,同时会有一个隐藏的全局MPMoviePlayerController,当屏幕翻转全屏时,调用全局的MPMoviePlayerController。
当滑动tableview时,显示正中间的播放视频。
滑动切换时,要让前一个MPMoviePlayerController停止播放,并且为了缓解内存,要设置MPMoviePlayerController = nil。同时要让下一个要播放的MPMoviePlayerController开始准备播放。
这时快速滑动,并且来回切换某两个视频,有很大概率会崩溃在[self.moviewPlayController prepareToPlay],并且报出一条错误:
*****Assertion failure in -[MPMoviePlayerControllerNew _moviePlayerDidBecomeActiveNotification:], /SourceCache/MediaPlayer/MobileMusicPlayer-2770.3.5/SDK/MPMoviePlayerController.m:1385
问题分析:
_moviePlayerDidBecomeActiveNotification
这个错误明显是一个系统通知,而且这条通知是无法在公开API里查到的,那么这就是一个系统内部使用的通知,而且苹果官方认为这个通知不需要开发者控制。
通过查找相关问题和资料,找到一些可供参考的内容,先抛出相关资料
stackoverflow:
一个有关的邮件记录:
http://www.mail-archive.com/cocoa-dev@lists.apple.com/msg68041.html
如果你真的为这个bug,或者相关的问题困惑,请一定先看看这些资料。
有可能是以下原因:
当前一个MPMoviePlayerController被释放时,为了获得播放器的各种状态,添加了很多的系统通知,如MPMediaPlaybackIsPreparedToPlayDidChangeNotification这种。但是在更换MPMoviePlayerController时要移除这个通知,如果不添加具体是哪个播放器添加了这个通知,很可能会出现移除的是新播放器的通知信息
添加一段描述: After playing with it for a bit, I found that the player's loadState property >is set to (MPMovieLoadStatePlayable | MPMovieLoadStatePlaythroughOK) when >playback finishes normally or MPMovieLoadStateUnknown when it's stopped >because another player instance has grabbed control. I've added a test that >prevents the queueing if the loadState is MPMovieLoadStateUnknown and that >seems to work just fine. 大概翻译一下: 当播放器播放结束时,或者LoadState处于MPMovieLoadStateUnknown状态时停止播放这个播放器,会出现我们已知的这个报错。原因也许就是新的播放器获得播放控制时,上一个播放器还处于激活状态,而新播放器调用play方法时再次激活出现错误。当在MPMovieLoadStateUnknown状态时添加相关判断后,播放器就正常了。
其实MPMOovieLoadStateUnknown这个命名就很有趣,貌似上层封装时检查到了播放器会在停止,开始状态中间 处于一种未知的状态,而且这个状态会持续1秒左右,好像这个状态是切换系统播放状态的准备时间。在这个状态下调 用播放器的stop方法或者play方法会报错。
解决方案:
如果是情况1,按照这个模式添加系统通知,并且在移除时也添加object属性:
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
[center addObserver:self
selector:@selector(moviePlaybackStateChanged:)
name:MPMoviePlayerPlaybackDidFinishNotification
object:self.movieController];
如果是情况2,那么就要在具体报错的位置添加判断。比如我遇到这个地方就可以在prepareToPlay的地方添加判断,给系统2秒钟去修改这个状态(谁让咱不能自己改呢╮(╯_╰)╭):
if(self.moviePlayerController.loadState == MPMovieLoadStateUnknown){
[self.moviePlayerController performSelector:@selector(prepareToPlay) withObject:nil afterDelay:2];
}
else{
[self.moviePlayerController prepareToPlay];
}
同时在移除播放器,为了防止在移除时都还没有调用这个延迟两秒的prepareToPlay方法,别忘了添加cancel方法
[NSObject cancelPreviousPerformRequestsWithTarget:self.moviePlayerController selector:@selector(prepareToPlay) object:nil];
以上,这个问题就解决的七七八八了,具体情况,等测试反馈咯。