2014-10-08 48 views
25

我正在創建一個簡單的媒體播放器應用程序。我的應用程序在第一個鏈接播放時崩潰,並在uitableview中點擊第二個鏈接。AVPlayer被釋放,而關鍵值觀察員仍然註冊了它

- (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"); 
     } 
    } 
} 

當應用程序崩潰時,我收到了此消息。

***終止應用程序由於未捕獲的異常「NSInternalInconsistencyException」,原因:「一個實例 類AVPlayer的0x165297c0被釋放,而鍵值觀察家仍然 其註冊。現有的觀測信息: (背景:爲0x0,物業:0x1661d5d0>)」

應用程序崩潰只在IOS 8 IOS 7工作正常。 我在做什麼錯?

回答

45

我有類似的問題。它在iOS 7中運行良好,現在它在iOS 8中崩潰。

解決方案是在釋放對象之前刪除觀察者。

當更換或分配一個新對象的一員,你釋放舊的對象,所以你需要先刪除觀察者:

-(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]; 
} 
+0

我把這個如果(球員=零!) { 如果(player.currentItem =零!) { [player.currentItem removeObserver:自forKeyPath:@ 「狀態」]; } }而不是if(player!= nil) [player removeObserver:self forKeyPath:@「status」];併爲我工作很好。 – 2014-11-21 05:26:05

+0

嗨,大家好,我也遇到了這個問題,正在尋找最近2天的解決方案。請幫我解決這個問題。 我在這裏發佈了問題 - http://stackoverflow.com/questions/27838356/avplayeritem-was-deallocated-while-key-value-observers-were-still-registered-wit – 2015-01-08 14:36:44

+1

我實現你的代碼,但得到錯誤 因未捕獲異常'NSRangeException'而終止應用,原因:'無法從中刪除關鍵路徑「狀態」的觀察者,因爲它未註冊爲觀察者。 – Hardik 2015-01-09 04:16:29

2

使用KVO時,您必須在addObserver:forKeyPath:options:context:之間撥打電話removeObserver:forKeyPath:(請參閱KVO programming guide)以平衡呼叫。

嘗試在停止按鈕被點擊時,將視圖控制器作爲觀察者移除,例如,

- (IBAction)btnStop_Click:(id)sender { 
    [[player currentItem] removeObserver:self forKeyPath:@"timedMetadata"]; 
} 
+0

應用程序崩潰。 Crash Log:'無法從中刪除關鍵路徑「timedMetadata」的觀察者,因爲它沒有註冊爲觀察者。應用程序僅在IOS 8設備中崩潰。 – 2014-10-08 12:57:44

+1

mmcombe是正確的,除了錯誤指的是AVPlayer的狀態'KVO。只需將他的答案更改爲[[player] removeObserver:self forKeyPath:@「status」]; – MDB983 2014-10-08 14:37:39

+0

我的應用程序在IOS 8中崩潰,以下是我的崩潰日誌:「終止應用程序,由於未捕獲異常'NSInternalInconsistencyException',原因:'AVPlayerItem類的實例0x15edf250被釋放,而鍵值觀察者仍在其中註冊。 – 2014-11-11 13:03:46

1
-(void)viewWillDisappear:(BOOL)animated 
{ 
[self.player removeObserver:self forKeyPath:@"status" context:nil]; 
} 
+0

你能提供圍繞您的解決方案一點背景知識? – wogsland 2017-02-16 13:08:26

+1

雖然這個代碼片段是受歡迎的,並且可能會提供一些幫助,但它會[如果包含解釋](/ meta.stackexchange.com/q/114762)的* how *和* why *會大大改進,這將解決問題。請記住,你正在爲將來的讀者回答這個問題,而不僅僅是現在問的人!請編輯您的答案以添加解釋,並指出適用的限制和假設。 – 2017-02-16 13:30:20

0

使用AVPlayer的時候我也滿足了類似的問題,崩潰日誌信息說:

AVKeyPathFlattener類的實例0x174034600被解除分配,而鍵值觀察者仍在其中註冊。現有的觀測信息:(背景:爲0x0,物業:0x17405d6d0>)

至於什麼蘋果推薦,我本來是增加觀測後初始化我AVPlayerItem對象,並在觀察者的dealloc方法去除觀測。因爲我的觀察者類在我的AVPlayerItem對象上保留了很強的引用,所以在我的觀察者對象被釋放之前不應該釋放它。我真的不知道爲什麼會發生這種情況。

所以我試着用BlocksKit解決了這個問題,它現在對我來說工作的很好。

相關問題