AVPlayer被重新分配,而关键价值观察员仍然在注册

我创build一个简单的媒体播放器应用程序。 我的应用程序崩溃时,第一个链接播放,我点击第二个链接在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"); } } } 

应用程序崩溃时,我收到了这条消息。

***终止应用程序由于未捕获的exception“NSInternalInconsistencyException”,原因:“AVPlayer类的实例0x165297c0被释放,而键值观察员仍然注册了它。 当前观察信息:(上下文:0x0,属性:0x1661d5d0>)

应用程序崩溃只在IOS 8 IOS 7工作正常。 我做错了什么?

我有一个类似的问题。 它在iOS 7中运行良好,现在它在iOS 8中崩溃。

解决方法是在释放对象之前移除观察者。

当你为一个成员replace或者分配一个新的对象的时候,你正在释放这个旧对象,所以你需要首先删除这个观察者:

 -(void) setupAVPlayerForURL: (NSURL*) url1 { AVAsset *asset = [AVURLAsset URLAssetWithURL:url1 options:nil]; AVPlayerItem *anItem = [AVPlayerItem playerItemWithAsset:asset]; if (player != nil) [player removeObserver:self forKeyPath:@"status"]; player = [AVPlayer playerWithPlayerItem:anItem]; [player addObserver:self forKeyPath:@"status" options:0 context:nil]; } 

和btnPlayClick类似(在没有按下btnStop_Click的情况下按下):

 - (IBAction)btnPlay_Click:(id)sender { if (player != nil && [player currentItem] != nil) [[player currentItem] removeObserver:self forKeyPath:@"timedMetadata"]; AVPlayerItem *item = player.currentItem; [item addObserver:self forKeyPath:@"timedMetadata" options:NSKeyValueObservingOptionInitial| NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld| NSKeyValueObservingOptionPrior context:nil]; [player play]; } 

使用KVO时,必须在调用addObserver:forKeyPath:options:context:时调用removeObserver:forKeyPath:请参阅KVO编程指南 )。

尝试删除视图控制器作为观察员停止button时,例如

 - (IBAction)btnStop_Click:(id)sender { [[player currentItem] removeObserver:self forKeyPath:@"timedMetadata"]; } 
 -(void)viewWillDisappear:(BOOL)animated { [self.player removeObserver:self forKeyPath:@"status" context:nil]; }