20

私はiPhone4SでInstrumentsを実行しています。私はこのメソッド内でAVAudioPlayerを使用しています:

-(void)playSound{
    NSURL *url = [self.word soundURL];
    NSError *error;
    audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error];
    if (!error) {
        [audioPlayer prepareToPlay];
        [audioPlayer play];
    }else{
       NSLog(@"Problem With audioPlayer on general card. error : %@ | url %@",[error description],[url absoluteString]);
}

サウンドファイルを再生するとリークが発生します。

リークされたオブジェクト:

1.1。

オブジェクト:NSURL

責任ある図書館:財団

責任あるフレーム:Foundation-[NSURL(NSURL)allocWithZone:]

2.2。

オブジェクト:_NSCFString

責任ある図書館:財団

責任あるフレーム:Foundation-[NSURL(NSURL)initFileURLWithPath:]

Instrumentsは私のコードを直接指していないので、リークの理由を見つけるのは難しいと思います。

私の質問

リークの原因は何ですか? またはコードに責任がない場合、どうすればリークを見つけることができますか?

編集 これはInstrumentsサイクルビューのスキーマです: ここに画像の説明を入力してください Thanks Shani

4

5 に答える 5

19

Appleのコードのリークのようです...私は両方を使ってみました

  • -[AVAudioPlayer initWithData:error:]
  • -[AVAudioPlayer initWithContentsOfURL:error:]

最初のケースでは、割り当てられたAVAudioPlayerインスタンスは渡されたを保持しますNSData。2番目では、渡されたNSURLものが保持されます。

渡されたNSDataオブジェクトの保持/解放履歴を示すInstrumentsウィンドウのスクリーンショットをいくつか添付しました。

ここに画像の説明を入力してください

次に、AVAudioPlayerオブジェクトがC ++オブジェクトを作成AVAudioPlayerCppし、NSDataを再び保持していることがわかります。

ここに画像の説明を入力してください

後でAVAudioPlayerオブジェクトが解放されると、NSDataが解放されますが、関連付けられた...からの解放呼び出しはありませAVAudioPlayerCppん(添付の画像からわかります)

NSData / NSURLのリークを回避したい場合は、メディアを再生するために別のソリューションを使用する必要があるようです。

これが私のテストコードです:

-(void)timerFired:(NSTimer*)timer
{
    NSString * path = [[ NSBundle mainBundle ] pathForResource:@"song" ofType:@"mp3" ] ;

    NSError * error = nil ;
    NSData * data = [ NSData dataWithContentsOfFile:path options:NSDataReadingMapped error:&error ] ;
    if ( !data )
    {
        if ( error ) { @throw error ; }
    }

    AVAudioPlayer * audioPlayer = data ? [[AVAudioPlayer alloc] initWithData:data error:&error ] : nil ;
    if ( !audioPlayer )
    {
        if ( error ) { @throw error ; }
    }

    if ( audioPlayer )
    {
        [audioPlayer play];
        [ NSThread sleepForTimeInterval:0.75 ] ;
        [ audioPlayer stop ] ;
    }
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // ...
    [ NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector( timerFired: ) userInfo:nil repeats:YES ] ;
    // ...
    return YES;
}
于 2012-09-30T07:58:39.360 に答える
1

以前の回答と同様に、私自身の調査とAppleデベロッパフォーラムでの議論はすべて、iOSバージョン6.0、6.0.1、および6.0.2にも言える限り、Apple自身のライブラリに存在する問題を指摘しています。

iOS 6.1でこの問題が修正され、リークが表示されなくなりました。

残念ながら、これは、iOSのバージョン6.0、6.0.1、または6.0.2を実行している電話でアプリが実行されると思われる場合、これらのケースのリークを修正するための回避策を実行する必要があることを意味します。

知っておくとよいことは、AVAudioPlayerの初期化に使用されたもののretainCountは、他のすべてが意図したとおりにクリアされている場合、1のように見えることです。

私自身の回避策は、オーディオ再生を独自のクラスにカプセル化することです。このクラスでは、-fno-objc-arcコンパイル時にプリプロセッサフ​​ラグを使用して手動でメモリ処理を行います。

すべてをリリースするときは、実際にリリースを開始する前に、初期化に使用したNSURLの保持カウントを取得するようにします(NSDataで初期化した場合も同じように機能します)。

他のすべてが正しく処理されている場合は、今では1または2になっているはずなので、適切な回数だけ解放します。

また、リリースを開始する前に、必ず保持カウントを取得してください。そうしないと、バグが修正されたiOSバージョンで解放されたオブジェクトにアクセスしようとします。

于 2013-02-07T22:01:14.013 に答える
0

これは、Appleライブラリ自体の問題です。多くの投稿(stackoverflowでも)が同様の問題を報告しています。ここでできることは何もありません。

于 2012-09-25T18:11:55.850 に答える
0

私の理解では、ARCプロジェクトで作業する場合、開発者としてのあなたは保持/リリースを担当しなくなります。したがって、問題はAppleのライブラリにあり、コードにはありません。

于 2012-09-25T19:20:39.453 に答える
0

これが本当にAppleのライブラリのバグである場合、これはそれほど楽しい回避策ではありません。

問題のクラスについては、アークが有効にならないようにしてください。

これは、ターゲットのビルドフェーズに進むことで実行できます。
コンパイルソースドロップダウンに移動し、クラスの.mファイルを見つけます。-fno-objc-arcコンパイラフラグ列を入力してください

残念ながら、クラスを調整し、手動でメモリを管理する必要があります。

アーク対応にならないようにクラスを構成するためのより詳細な説明は、SOに関する別の質問のこの回答にありました

編集

AVAudioPlayerの動作を別のクラスにカプセル化し、そのクラスをすべての再生に使用できると思います。その場合、-fno-objc-arc1つのファイルに設定することができ、アプリ全体のメモリ管理に取り組む必要はありません。

于 2012-09-27T23:59:56.447 に答える