我正在创建一个简单的媒体播放器应用 . 我的应用程序在播放第一个链接时崩溃,我点击了uitableview中的第二个链接 .
- (void)viewDidLoad {
[super viewDidLoad];
arrURL = [NSArray arrayWithObjects: @"http://yp.shoutcast.com/sbin/tunein-station.pls?id=148820", @"http://www.kcrw.com/pls/kcrwmusic.pls",@"http://yp.shoutcast.com/sbin/tunein-station.pls?id=175821",@"http://yp.shoutcast.com/sbin/tunein-station.pls?id=148820",@"http://yp.shoutcast.com/sbin/tunein-station.pls?id=70931",nil];
url = [[NSURL alloc] init];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [arrURL count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = @"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] ;
}
cell.textLabel.text = [arrURL objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
selectedSongIndex = indexPath.row;
url = [[NSURL alloc] initWithString:[arrURL objectAtIndex:indexPath.row]];
[self setupAVPlayerForURL:url];
[player play];
//[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
- (IBAction)btnPlay_Click:(id)sender {
[player play];
AVPlayerItem *item = player.currentItem;
[item addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld| NSKeyValueObservingOptionPrior context:nil];
}
- (IBAction)btnPause_Click:(id)sender {
[player pause];
}
- (IBAction)btnStop_Click:(id)sender {
[player pause];
}
-(void) setupAVPlayerForURL: (NSURL*) url1 {
AVAsset *asset = [AVURLAsset URLAssetWithURL:url1 options:nil];
AVPlayerItem *anItem = [AVPlayerItem playerItemWithAsset:asset];
player = [AVPlayer playerWithPlayerItem:anItem]; **//Application Crashed**
[player addObserver:self forKeyPath:@"status" options:0 context:nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if([keyPath isEqualToString:@"timedMetadata"])
{
AVPlayerItem *item = (AVPlayerItem *)object;
NSLog(@"Item.timedMetadata: %@",item.timedMetadata);
NSLog(@"-- META DATA ---");
// AVPlayerItem *pItem = (AVPlayerItem *)object;
for (AVMetadataItem *metaItem in item.timedMetadata) {
NSLog(@"meta data = %@",[metaItem commonKey]);
NSString *key = [metaItem commonKey]; //key = publisher , key = title
NSString *value = [metaItem stringValue];
NSLog(@"key = %@, value = %@", key, value);
if([[metaItem commonKey] isEqualToString:@"title"])
{
self.lblTitle.text = [metaItem stringValue];
}
}
}
if (object == player && [keyPath isEqualToString:@"status"]) {
if (player.status == AVPlayerStatusFailed) {
NSLog(@"AVPlayer Failed");
} else if (player.status == AVPlayerStatusReadyToPlay) {
NSLog(@"AVPlayer Ready to Play");
} else if (player.status == AVPlayerItemStatusUnknown) {
NSLog(@"AVPlayer Unknown");
}
}
}
App崩溃后我收到了这条消息 .
***因未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因是:'AVPlayer类的实例0x165297c0已取消分配,而键值观察者仍在其中注册 . 当前观察信息:(上下文:0x0,属性:0x1661d5d0>)'
在IOS 7中仅在IOS 8中崩溃的应用程序正常工作 . 我做错了什么?
5 回答
我遇到了类似的问题 . 它在iOS 7中运行良好,现在它在iOS 8中崩溃了 .
解决方案是在释放对象之前移除观察者 .
当您为成员替换或分配新对象时,您将释放旧对象,因此您需要先删除观察者:
同样在btnPlayClick中(如果在没有按下btnStop_Click的情况下按下它):
使用KVO时,您必须 balancer 对
addObserver:forKeyPath:options:context:
的调用以及对removeObserver:forKeyPath:
的调用(请参阅KVO programming guide) .点击停止按钮时尝试以观察者的身份移除视图控制器,例如
我在使用AVPlayer时遇到了类似的问题,崩溃日志信息说:
正如Apple推荐的那样,我最初做的是在初始化我的AVPlayerItem对象后添加观察者,并在观察者的dealloc方法中删除观察者 . 因为我的观察者类对我的AVPlayerItem对象保留了强引用,所以在我的观察者对象被释放之前不应该释放它 . 我真的不知道为什么会这样 .
所以我尝试使用BlocksKit解决了这个问题,它现在对我来说很好 .
在使用
@try @catch
删除观察者之前,首先验证密钥是否被观察是明智的,如下所示: