在利用AVPlayer
播放网络 mp3 时,因为有监听状态,所以移除监听是必须的
不然会出现以下错误:
An instance 0x174016100 of class AVPlayerItem was deallocated while key value observers were still registered with it.
不移除观察者时,导致的崩溃:
Trapped uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x174016100 of class AVPlayerItem was deallocated while key value observers were still registered with it. Current observation info: (
Context: 0x0, Property: 0x174848d00>
Context: 0x0, Property: 0x174841f20>
Context: 0x0, Property: 0x174849ff0>
)'
然而,有个蛋疼的操作出现了
当移除观察者时
另外一个Bug出现了
Trapped uncaught exception 'NSInvalidArgumentException', reason: 'An instance of AVPlayer cannot remove a time observer that was added by a different instance of AVPlayer.'
这移除不行!
这不移除也不行!
这要怎么玩??
1.播放音频
1.1移除前一个音频的监听状态(如果存在)
1.2添加新的监听状态
2.状态监听回调方法
2.1成功则播放
2.2失败
2.2.1第1次失败,尝试再次播放 -> 走步骤1
2.2.2第2次失败,移除监听状态
就是在步骤 2.2.2
,出现了进退两难的情况
既然移除是必须的
那就只能走移除!
但是移除又会导致:
Trapped uncaught exception 'NSInvalidArgumentException', reason: 'An instance of AVPlayer cannot remove a time observer that was added by a different instance of AVPlayer.'
只能前进
如何后退呢?
如果你能想到的话
你已经知道我要说什么了
如果你还没想到
继续往下看
iOS中有个捕获异常,防止崩溃的机制:@try @catch
@try {
// 可能存在异常
[self.player removeTimeObserver:self.timeObserver];
} @catch (NSException *exception) {
// 查看异常
NSLog(@"RemoveObserver:%@",exception);
} @finally {
// 去掉 finally 也可以
}
虽然这个捕获异常的机制
捕获的异常有限
但这里确实能防止
应用崩溃
Nice!
2020-07-28 18:04:36
在移除监听时,应该判断timeObserver
是否存在
并在移除后置空
- (void)removeObserver
{
if (self.player.currentItem) {
@try {
[self.player.currentItem removeObserver:self forKeyPath:@"status"];
[self.player.currentItem removeObserver:self forKeyPath:@"playbackLikelyToKeepUp"];
[self.player.currentItem removeObserver:self forKeyPath:@"playbackBufferEmpty"];
[self.player replaceCurrentItemWithPlayerItem:nil];
if (self.timeObserver) {
[self.player removeTimeObserver:self.timeObserver];
self.timeObserver = nil;
}
} @catch (NSException *exception) {
NSLog(@"removeObserver:%@",exception);
} @finally {
}
}
}
就是因为前面没置空
所以导致后面移除时
跟AVPlayer
匹配不上
2020-07-28 18:09:13
遇到一个加载 mp3 url 后
无法播放的Bug:
Error Domain=AVFoundationErrorDomain Code=-11819 "无法完成操作" UserInfo={NSLocalizedDescription=无法完成操作, NSLocalizedRecoverySuggestion=请稍后再试。}
接着,所以其他的 mp3 url 资源都无法播放了
所有报错都是这样:
Error Domain=AVFoundationErrorDomain Code=-11819 "无法完成操作" UserInfo={NSLocalizedDescription=无法完成操作, NSLocalizedRecoverySuggestion=请稍后再试。, NSURL=https://xxx/xxx/xxx.mp3, NSUnderlyingError=0x174a51670 {Error Domain=NSOSStatusErrorDomain Code=268435459 "(null)"}}
代码使用了同一个AVPlayer
实例
猜测原因是
AVPlayer
内部有缓存
导致后面加载的 url 都不请求了
最终尝试如下操作
解决了这个蛋疼的问题
在回调方法里
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
针对播放失败状态所做的处理
if ([keyPath isEqualToString:@"status"]) {
switch ([[change valueForKey:@"new"] integerValue]) {
case AVPlayerItemStatusFailed: {
NSError * error = _player.currentItem.error;
if (error) {
NSInteger code = erro.code;
NSInteger count = erro.userInfo.count;
if (code == -11819 &&
count == 2) {
[self removeObserver];
_player = nil;
}
}
// 可以尝试重新加载
// 或者其他操作
}
break;
}
}
有些音频即使再次加载
也还是不能播放
错误有2种:
第一种:-11800,AVErrorUnknown,未知错误 T_T
Error Domain=AVFoundationErrorDomain Code=-11800 "这项操作无法完成" UserInfo={NSLocalizedFailureReason=发生未知错误(-16041), NSLocalizedDescription=这项操作无法完成, NSUnderlyingError=0x2801d9a70 {Error Domain=NSOSStatusErrorDomain Code=-16041 "(null)"}}
第二种:byte range length mismatch T_T
Error Domain=NSURLErrorDomain Code=-1 "未知错误" UserInfo={NSLocalizedDescription=未知错误, NSUnderlyingError=0x283db2be0 {Error Domain=CoreMediaErrorDomain Code=-12939 "byte range length mismatch - should be length 16384 is length 24137" UserInfo={NSDescription=byte range length mismatch - should be length 16384 is length 24137, NSURL=http://xxx/xxx/xxx.mp3}}}
既然系统的下载不行
那就尝试手动下载
由于音频不是很大
所以采取先下载后播放
的策略
最终解决了这2个蛋疼的bug!
https://github.com/xjh093/JHVerificationCodeView