2009-07-27 35 views
2

マルチスレッドiPhoneアプリケーションでメモリ管理関連の質問があります。 それがメインUIスレッドとは別のスレッドで呼び出され、我々はこの方法を持っているとしましょう:あなたが見ることができるように[NSAutoreleasePool release]でマルチスレッドiPhoneアプリがクラッシュする

- (BOOL)fetchAtIndex:(NSUInteger)index 
{ 
    NSURL *theURL = [NSURL URLWithString:[queryURLs objectAtIndex:index]]; 
    // Pay attention to this line: 
    NSData *theData = [[NetworkHelper fetchFromNetwork:theURL] retain]; 

    // Some code here... 

    // Now what should I do before returning result? 
    //[theData release]; ?? 
    //[theData autorelease]; ?? 
    return YES; 
} 

、私は戻って私のネットワーク運用から得たNSDataを保持しています。問題は、なぜ私はメソッドの最後にそれをリリース(または自動解放)してはいけないのですか? 私がそれを働かせた唯一の方法は、最初にretainを使用し、何もしないことです。私がスレッドのNSAutoreleasePoolをリリースしたときに私が他の組み合わせを使用した場合(retain、次にreleaseまたはautorelease)、私のプログラムはEXC_BAD_ACCESSでクラッシュします。 私は何が欠けていますか?

FYI、ここのスレッドの主なコードは次のとおりです。あなたの助けのための

- (void)threadedDataFetching; 
{ 
    // Create an autorelease pool for this thread 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    // Reload data in separate thread 
    [self fetchAtIndex:0]; 

    // Signal the main thread that fetching is finished 
    [self performSelectorOnMainThread:@selector(finishedFetchingAll) withObject:nil waitUntilDone:NO]; 

    // Release all objects in the autorelease pool 
    [pool release]; // This line causes EXC_BAD_ACCESS 
} 

ありがとう!

答えて

3

あなたは(retainまたはimplictlyと方法により、いずれかを使用:initnew、または自分の名前でcopyを)自分自身を保持していないものを解放してはいけません。

fetchFromNetworkの結果を保持する場合は、それを解放する必要があります。 releaseautoreleaseの両方が動作する必要があります(releaseの後にオブジェクトに触れないでください。releaseの後にフィールド/変数をnilに設定するのが最も安全です)。

データを保持していない場合は、保持する必要はありません。 [NetworkHelper fetchFromNetwork]は、自動解放されたオブジェクトを返す必要があります。疑いで、リーキー側に誤る場合

NSData *data = [[NSData alloc] init]; 
// stuff happens 
return [data autorelease]; 

または

NSData *data = [otherObject dataFromOtherObject]; 
// stuff happens 
return data; // don't (auto)release, since you haven't retained 

と「リーク」楽器やLLVM checkerを介してアプリケーションを実行します。fetchFromNetworkの体はこのようになります。

+0

ありがとうございます。 実際、fetchFromNetworkは2番目のコードサンプルのようでした。 NSData * data = [otherObject dataFromOtherObject]; ... 返品[データ自動取り消し]; //ここで間違っている! 私はそれをクライアントコードに保持しなければならなかったのです。 誤った-autorelease呼び出しを削除してから、クライアント側で-retainコードを削除しましたが、今はすべて問題ありません。 ありがとう! – Romain

0

あなたが別のスレッドにいるという事実は、ここではあまり関係ありません。メモリ管理は同じで、NSDataの保持/解放のバランスをメインスレッドと同じにする必要があります。 autoreleaseプールを流出させたときにクラッシュするという事実は、あなたがここで私たちに示していないDataで何かをしたことを示唆しています。誰かにそれを保持することを要求しているデータで何をしていますか?

+0

あなたが、私は他のコメントで書いたように、私はそれが働いていたので、このコードでそれを保持する_had_ので、fetchFromNetworkはNSDataオブジェクトを自動解放して、右だが、バグのある部分はfetchFromNetwork方法にありました。おかげさまで – Romain

0

他の人が指摘しているように、実際にはこのインスタンスではマルチスレッドとは関係ありません。アップルが製造するObjective C Memory Management Guidelinesを読む価値があります。

あなたが明示的にあなたが[init]を自分で明示しているオブジェクトであれば、あなた自身が責任を持ってクリーンアップする必要があります。メソッドからこの値を返す場合は、メソッドを自動解放する必要があります。

発信者がinitWithで始まらないオブジェクト([Foo emptyFoo]など)は、呼び出し元がリソースを所有する(つまり、自動解放する)責任があります。

オブジェクトを渡してメソッド呼び出しの外に保持したい場合(つまり、インスタンスフィールドに保存します)、それを保持する必要があります。完了したら、通常はデストラクタで解放します。 Objective Cのプロパティを使用している場合、それを@retainとして定義すると自動的にこの動作が実行されます。デストラクタでは、プロパティをnilに設定するだけで済みます。

関連する問題