2014-10-08 17 views
25

Tworzę prostą aplikację odtwarzacza multimediów. Moja aplikacja ulega awarii po uruchomieniu pierwszego linku i kliknięciu drugiego linku w uitableview.AVPlayer został zwolniony, podczas gdy obserwatorzy wartości klucza nadal go zarejestrowali.

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

Dostałem tę wiadomość, gdy aplikacja się zawiesiła.

*** Zakończenie aplikację spowodowane nieprzechwyconego wyjątku „NSInternalInconsistencyException”, powód: „Instancja 0x165297c0 z klasy AVPlayer został zwalniane jednocześnie kluczowe wartości obserwatorzy wciąż zarejestrowany z nim. Aktualny informacji obserwacja: (Kontekst: 0x0, Własność: 0x1661d5d0>)”

aplikacja zawieszała się tylko w IOS 8 w iOS 7 działa poprawnie. Co robię źle?

Odpowiedz

45

Miałem podobny problem. W iOS 7 działało dobrze, a teraz ulega awarii w systemie iOS 8.

Rozwiązaniem było usunięcie obserwatora przed zwolnieniem obiektu.

Po wymianie lub przydzielić nowy obiekt dla członka, masz zwolnienie starego obiektu, więc trzeba usunąć obserwatora pierwszy:

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

i podobnie w btnPlayClick (w przypadku, gdy zostanie naciśnięty bez btnStop_Click jest wciśnięty):

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

Ja to if (player = nil!) { if (player.currentItem = nil!) { [player.currentItem removeObserver: self forKeyPath: @ "status"]; } } zamiast if (player! = Nil) [player removeObserver: self forKeyPath: @ "status"]; i działa świetnie dla mnie. –

+0

Witajcie, ja też utknąłem z tym problemem, szukałem rozwiązania przez ostatnie 2 dni. Proszę, pomóż mi to naprawić. Zamieściłem tutaj pytanie - http://stackoverflow.com/questions/27838356/avplayeritem-was-deallocated-while-key-value-observers-were-still-registered-wit –

+1

Zaimplementowałem twój kod, ale dostaję błąd Kończenie aplikacji z powodu nieprzechwyconego wyjątku "NSRangeException", powód: "Nie można usunąć obserwatora dla ścieżki klucza" status "z , ponieważ nie jest zarejestrowany jako obserwator. ' – Hardik

2

Podczas korzystania z KVO należy zrównoważyć połączenia z numerami addObserver:forKeyPath:options:context:, dzwoniąc pod numer removeObserver:forKeyPath: (patrz: KVO programming guide).

Spróbuj usunąć kontroler widoku jako obserwator po dotknięciu przycisku Stop, np.

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

Aplikacja uległa awarii. Crash Log: "Nie można usunąć obserwatora dla ścieżki klucza" timedMetadata "z , ponieważ nie jest zarejestrowany jako obserwator. ' Aplikacja uległa awarii tylko w urządzeniu IOS 8. –

+1

mmcombe jest poprawne, poza tym błąd odnosi się do statusu AVKlayer 'KVO.po prostu zmień jego odpowiedź na [[player] removeObserver: self forKeyPath: @ "status"]; – MDB983

+0

Moja aplikacja ulega awarii w IOS 8, a następujący jest mój dziennik awarii: "Kończenie aplikacji z powodu nieprzechwyconego wyjątku" NSInternalInconsistencyException ", powód:" Wystąpiła dezalokacja instancji 0x15edf250 klasy AVPlayerItem, podczas gdy obserwatorzy wartości klucza nadal byli z nią rejestrowani. " –

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

można podać trochę kontekst wokół rozwiązania? – wogsland

+1

Chociaż ten fragment kodu jest mile widziany i może zapewnić pomoc, byłby [znacznie ulepszony, gdyby zawierał wyjaśnienie] (// meta.stackexchange.com/q/114762) * how * i * why * to rozwiązuje problem. Pamiętaj, że odpowiadasz na pytanie dla czytelników w przyszłości, a nie tylko pytasz teraz! Proszę [edytuj] swoją odpowiedź, aby dodać wyjaśnienie i podać, jakie ograniczenia i założenia mają zastosowanie. –

0

zrobiłem spotkać podobny problem przy korzystaniu AVPlayer, informacje dziennika krach mówi:

Instancja 0x174034600 klasy AVKeyPathFlattener została zwolniona, podczas gdy obserwatorzy wartości klucza nadal byli z nią rejestrowani. Aktualny informacji spostrzeżenie: (Kontekst: 0x0, Własność: 0x17405d6d0>)

Jak co zaleca jabłko, co początkowo nie dodaje obserwator po inicjalizacji mojego obiektu AVPlayerItem i usunąć obserwatora w metodzie dealloc obserwatora. Ponieważ moja klasa obserwatorów utrzymywała silne odniesienie do mojego obiektu AVPlayerItem, więc nie powinna być deallocated zanim obiekt obserwatora został zwolniony. Naprawdę nie wiem, dlaczego tak się dzieje.

Tak więc próbowałem rozwiązać ten problem za pomocą BlocksKit, to działa dobrze dla mnie teraz.