2

オーディオを再生するアプリを作成しており、ロック画面が を通じて更新されるように設定しましたがMPNowPlayingInfoCenter、問題が発生しました。

一見ランダムなタイミングで、EXC_BAD_ACCESS再生中の情報を更新しようとするとエラーが発生します。

これを行うコードは次のとおりです。

- (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% の確率で機能しますが、アプリをバックグラウンドに戻すときや、オーディオ ファイルを変更するとき、またはランダムに、

[npInfoCenter setNowPlayingInfo:_activeMetadata];

投げEXC_BAD_ACCESSます。

また、次の_activeMetadataように宣言されています。

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

AVPlayer の作成時にインスタンス化されます。

    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すべてのフレームで CADisplayLink を介して呼び出されます。

例外を引き起こしている可能性のあるアイデアはありますか?

4

2 に答える 2

3

setNowPlayingInfoあなたはあまりにも頻繁に電話をかけていると思います。確かに、クラッシュすることはありませんがCADisplayLink、1 秒間に 60 回呼び出す必要はありません。

では、なぜ頻繁に電話をかけるのでしょうか。プログレスバーをスムーズに追跡したい場合は、まだ必要ありません。MPNowPlayingInfoPropertyElapsedPlaybackTime宣言から:

// 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.)

ps m4aファイルでコードを試してみたところ、durIntervalNotANumberが見つかりました。正しい期間とsetNowPlayingInfo1 回だけの呼び出しで、プログレス バーは正常に追跡され、何もクラッシュしませんでした。

于 2016-09-18T12:18:20.477 に答える
0

Apple は、iOS 10.3 以降でこのクラッシュを修正しました。そのため、iOS 10.2.1 以下をサポートする場合は、[MPNowPlayingInfoCenter defaultCenter].nowPlayingInfoプロパティを設定する頻度を調整してください。おそらく、プロパティの設定を 1 秒に 1 回だけに制限します。

于 2019-02-09T07:52:40.793 に答える