2014-10-08 7 views
25

Sto creando una semplice app per lettore multimediale. La mia App si blocca quando viene riprodotto il primo link e ho fatto clic sul secondo link in uitableview.AVPlayer è stato deallocato mentre gli osservatori dei valori chiave erano ancora registrati con esso

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

Ho ricevuto questo messaggio quando si è verificato un arresto anomalo dell'app.

*** Chiusura di applicazione a causa di eccezione non identificata 'NSInternalInconsistencyException', la ragione: 'Un'istanza 0x165297c0 di classe AVPlayer è stato deallocato, mentre gli osservatori di valore chiave erano ancora registrato con esso. Corrente informazioni osservazione: (Contesto: 0x0, di proprietà: 0x1661d5d0>)'

Applicazione caduto solo in IOS 8 in IOS 7 funziona bene. Cosa sto facendo male ??

risposta

45

Ho avuto un problema simile. Ha funzionato bene su iOS 7 e ora si blocca su iOS 8.

La soluzione era rimuovere l'osservatore, prima di rilasciare l'oggetto.

Quando si sostituisce o allocare un nuovo oggetto per un membro, si sta liberando il vecchio oggetto, quindi è necessario rimuovere l'osservatore prima:

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

E allo stesso modo in btnPlayClick (nel caso in cui viene premuto senza btnStop_Click premuto):

- (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

ho messo questo caso (giocatore = nil!) { se (player.currentItem = nil!) { [player.currentItem removeObserver: auto forKeyPath: @ "status"]; } } invece di if (player! = Nil) [player removeObserver: self forKeyPath: @ "status"]; e funziona benissimo per me. –

+0

Ciao ragazzi, sono anche bloccato con questo problema, cercavo una soluzione per gli ultimi 2 giorni. Per favore aiutami a risolvere questo problema. Ho postato la domanda qui - http://stackoverflow.com/questions/27838356/avplayeritem-was-deallocated-while-key-value-observers-were-still-registered-wit –

+1

ho implementato il codice ma ottengo errore Terminare l'app a causa dell'eccezione non rilevata "NSRangeException", motivo: "Impossibile rimuovere un osservatore per il percorso chiave" status "da perché non è registrato come osservatore." – Hardik

2

Quando si utilizza KVO è necessario bilanciare le chiamate a addObserver:forKeyPath:options:context: con le chiamate a removeObserver:forKeyPath: (vedere KVO programming guide).

Provare a rimuovere il controller di visualizzazione come osservatore quando si tocca il pulsante di arresto, ad es.

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

L'applicazione si è bloccata. Registro di crash: 'Impossibile rimuovere un osservatore per il percorso chiave "timedMetadata" da perché non è registrato come osservatore.' L'applicazione si è arrestata in modo anomalo solo nel dispositivo IOS 8. –

+1

mmcombusto è corretto, tranne che l'errore si riferisce allo stato di AVPlayer 'KVO.basta cambiare la sua risposta a [[player] removeObserver: self forKeyPath: @ "status"]; – MDB983

+0

La mia applicazione è bloccata in IOS 8 e il mio registro di arresto è il seguente: "Terminazione dell'app a causa di eccezione non rilevata 'NSInternalInconsistencyException', motivo: 'Un'istanza 0x15edf250 della classe AVPlayerItem è stata deallocata mentre gli osservatori dei valori chiave erano ancora registrati con esso." –

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

Si può fornire un po 'di contesto intorno alla vostra soluzione? – wogsland

+1

Sebbene questo snippet di codice sia benvenuto e possa fornire un aiuto, sarebbe [notevolmente migliorato se includesse una spiegazione] (// meta.stackexchange.com/q/114762) di * come * e * perché * questo risolve il problema problema. Ricorda che stai rispondendo alla domanda per i lettori in futuro, non solo la persona che chiede ora! Si prega di [modificare] la risposta per aggiungere una spiegazione e fornire un'indicazione di quali limitazioni e ipotesi si applicano. –

0

ho incontrato il problema simile quando si utilizza AVPlayer, informazioni di log incidente dice:

Un'istanza 0x174034600 della classe AVKeyPathFlattener è stata deallocata mentre gli osservatori dei valori chiave erano ancora registrati con esso. Corrente informazioni osservazione: (Contesto: 0x0, di proprietà: 0x17405d6d0>)

Come quello che raccomanda di Apple, quello che ho fatto in origine è l'aggiunta di osservatore dopo inizializzare il mio oggetto AVPlayerItem, e rimuovere osservatore metodo dealloc dell'osservatore. Perché la mia classe di osservatori ha mantenuto un forte riferimento sul mio oggetto AVPlayerItem, quindi non dovrebbe essere deallocato prima che il mio oggetto observer fosse deallocato. Non so davvero perché questo succede.

Quindi ho provato a risolvere questo problema utilizzando BlocksKit, per me funziona correttamente ora.

Problemi correlati