2016-09-18 2 views
2

Ich mache eine App, die Audio wiedergibt und ich habe es eingerichtet, so dass der Sperrbildschirm über MPNowPlayingInfoCenter aktualisiert wird, aber ich habe ein Problem festgestellt.MPNowPlayingInfoCenter werfen EXC_BAD_ACCESS

Zu scheinbar zufälligen Zeiten, bekomme ich eine EXC_BAD_ACCESS Fehler beim Versuch, die jetzt spielen Informationen zu aktualisieren.

Hier ist der Code, der so tut:

- (void)updatePlayback 
{ 
    if(!active) 
     return; 

    NowPlayingController* npc = [AudioController nowPlayingController]; 
    CMTime elapsed = player.currentTime; 
    Float64 elInterval = CMTimeGetSeconds(elapsed); 
    [npc setElapsed:elInterval]; 

    CMTime duration = player.currentItem.duration; 
    Float64 durInterval = CMTimeGetSeconds(duration); 
    [npc setRemaining:ceilf(durInterval - elInterval)]; 

    [npc setPlayPauseValue:isPlaying]; 
    if(durInterval > 0) 
    { 
     [npc setProgressValue:elInterval/durInterval]; 
     [npc setAudioDuration:durInterval]; 
    } 

    _activeMetadata[MPMediaItemPropertyPlaybackDuration] = @(durInterval); 
    _activeMetadata[MPNowPlayingInfoPropertyPlaybackRate] = @(isPlaying); 
    _activeMetadata[MPNowPlayingInfoPropertyElapsedPlaybackTime] = @(elInterval); 

    MPNowPlayingInfoCenter* npInfoCenter = [MPNowPlayingInfoCenter defaultCenter]; 
    if(npInfoCenter && _activeMetadata) 
    { 
     if([npInfoCenter respondsToSelector:@selector(setNowPlayingInfo:)]) 
     { 

//////////THE FOLLOWING LINE TRIGGERS EXC_BAD_ACCESS SOMETIMES//////////// 
      [npInfoCenter setNowPlayingInfo:_activeMetadata]; 
     } 

    } 
} 

99,9% der Zeit, dies funktioniert, aber manchmal, wenn die App in den Hintergrund resignieren oder wenn Audiodateien ändern oder nur zufällig,

[npInfoCenter setNowPlayingInfo:_activeMetadata]; 

wirft EXC_BAD_ACCESS.

Auch wird _activeMetadata erklärt wie:

@property (atomic, strong, retain) NSMutableDictionary* activeMetadata; 

Es instanziiert wird, wenn die AVPlayer erstellt:

AVAsset* asset = [AVAsset assetWithURL:[NSURL fileURLWithPath:path]]; 
    AVPlayerItem* playerItem = [AVPlayerItem playerItemWithAsset:asset]; 
    player = [AVPlayer playerWithPlayerItem:playerItem]; 

    CMTime duration = player.currentItem.duration; 
    NSTimeInterval durInterval = CMTimeGetSeconds(duration); 
    NSLog(@"%f", durInterval); 

    MPMediaItemArtwork* albumArtwork = [[MPMediaItemArtwork alloc] initWithImage:[downloader useCachedImage:CacheKeySeriesBanners withName:nil withURL:info[@"image"]]]; 
    NSDictionary* nowPlayingInfo = @{MPMediaItemPropertyTitle:ptString, 
            MPMediaItemPropertyArtist:spString, 
            MPMediaItemPropertyArtwork:albumArtwork, 
            MPMediaItemPropertyAlbumTitle:info[@"title"], 
            MPMediaItemPropertyPlaybackDuration:@(durInterval), 
            MPNowPlayingInfoPropertyPlaybackRate:@(1), 
            MPNowPlayingInfoPropertyElapsedPlaybackTime:@(0)}; 
    [[MPNowPlayingInfoCenter defaultCenter] setNowPlayingInfo:nowPlayingInfo]; 

    _activeMetadata = [nowPlayingInfo mutableCopy]; 

updatePlayback wird über einen CADisplayLink auf jedem Frame genannt.

Irgendwelche Ideen, was die Ausnahme verursachen könnte?

Antwort

2

Ich denke, Sie rufen setNowPlayingInfo viel zu oft. Zugegeben, es sollte wirklich nicht abstürzen, aber es gibt keine Notwendigkeit, CADisplayLink zu verwenden, um es 60 Mal pro Sekunde aufzurufen.

Warum rufen Sie es so oft an? Wenn es darum geht, dass Sie die Balkenanzeige problemlos fortschreiben können, brauchen Sie das nicht. Aus der MPNowPlayingInfoPropertyElapsedPlaybackTime Erklärung:

// The elapsed time of the now playing item, in seconds. 
// Note the elapsed time will be automatically extrapolated from the previously 
// provided elapsed time and playback rate, so updating this property frequently 
// is not required (or recommended.) 

P. S. Ich versuchte den Code mit einer m4a-Datei und fand durInterval war NotANumber. Mit der richtigen Dauer und setNowPlayingInfo nur einmal aufrufen, verfolgt die Fortschrittsleiste fein & nichts abgestürzt.

+0

Ich denke, du hast Recht. Ich denke, dass ich einen Fehler bekommen habe, weil ich den Inhalt von '_activeMetadata' zu häufig geändert habe und es wurde überschrieben, während es in das gerade spielende Zentrum kopiert wurde. Das Frame-Aktualisierungsintervall auf 2 fps anstelle von 60 fps zu reduzieren und eine Kopie des NSDictionary zu erstellen, bevor es den jetzt spielenden Informationen zugewiesen wird, scheint das Problem behoben zu haben. Seitdem habe ich keinen Unfall gehabt. – David

+0

Ich stimme dir zu, dass es nicht gut ist, es so oft zu nennen. Aber ich denke, es sollte nicht abstürzen, nur weil es sehr häufig aufgerufen wird. Ich bin auf das gleiche Problem gestoßen, wenn ich Tracks zu schnell gewechselt habe. Erstellen Sie eine Kopie des Wörterbuchs, bevor Sie es für mich repariert haben. Danke. – d4Rk

+0

@ d4Rk Eine Kopie des Wörterbuchs erstellen, bevor es repariert wurde? Ich bin immer noch stecken –