2011-01-18 9 views
3

NSOperationQueueでNSInvocationOperation型操作を実行していて、オブジェクトを自動解放するのが安全かどうか疑問に思っていました。つまり、各操作で開始されたスレッドが独自の自動解放プールを持つことが保証されている場合です。NSOperation内のオブジェクトを自動リリースするのは安全ですか?

私は、操作のためのドキュメント自動解放プールを見つけられませんでした.Appleのドキュメントを読むと、私自身の自動解放プールを定義する必要があることが実際に示唆されます。

ただし、 1)機器に漏れはありません。少なくとも、私自身の自動解放プールを操作に割り当てるときは、それ以上ではありません。

2)私はこのスタックトレースを見ることができますデバッガで探して:

#0 0x00fc3e82 in -[NSObject(NSObject) release]() 
#1 0x00faaa6c in CFRelease() 
#2 0x00fbf804 in __CFBasicHashDrain() 
#3 0x00faabcb in _CFRelease() 
#4 0x00fcfb8d in _CFAutoreleasePoolPop() 
#5 0x000edd0d in -[__NSOperationInternal start]() 
#6 0x000ed826 in ____startOperations_block_invoke_2() 
#7 0x94358024 in _dispatch_call_block_and_release() 
#8 0x9434a2f2 in _dispatch_worker_thread2() 
#9 0x94349d81 in _pthread_wqthread() 
#10 0x94349bc6 in start_wqthread() 

CFAutoreleasePoolがあるかのように見えるが - このオブジェクトを想定することが安全であるときに、すべての私の自動解放オブジェクトにリリースを呼び出します操作は完了ですか?

答えて

4

私はNSInvocationOperationは、操作のための自動解放プールを作成するかどうかをテストするための小さなプログラムを書いている:

#import <Foundation/Foundation.h> 

@interface MyClass : NSObject 
@end 

@implementation MyClass 
- (void)performSomeTask:(id)data 
{ 
    NSString *s = [[[NSString alloc] initWithFormat:@"hey %@", data] 
     autorelease]; 
    if ([[NSThread currentThread] isMainThread]) 
     NSLog(@"performSomeTask on the main thread!"); 
    else 
     NSLog(@"performSomeTask NOT on the main thread!"); 

    NSLog(@"-- %@", s); 
} 
@end 

int main(int argc, char *argv[]) { 
    MyClass *c = [MyClass new]; 

    if (argc == 2 && strcmp(argv[1], "nop") == 0) 
     [c performSomeTask:@"ho"]; 
    else { 
     NSInvocationOperation *op = [[NSInvocationOperation alloc] 
      initWithTarget:c 
       selector:@selector(performSomeTask:) 
        object:@"howdy"]; 
     NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
     [queue addOperation:op]; 
     [op waitUntilFinished]; 

     [op release]; 
     [queue release]; 
    } 

    [c release]; 

    return 0; 
} 

それは次のように動作します:「NOP」コマンドラインで渡された場合、それは意志メインスレッド上で、自動解放プールを使用せずに直接-performSomeTask:を実行してください。結果は次のようになります。

$ ./c nop 
*** __NSAutoreleaseNoPool(): Object 0x10010cca0 of class NSCFString autoreleased with no pool in place - just leaking 
performSomeTask on the main thread! 
-- hey ho 

-performSomeTask:の自動再生文字列はリークを引き起こします。

"nop"を渡さずにプログラムを実行すると、異なるスレッドのNSInvocationOperationを介して-performSomeTask:が実行されます。出力結果は次のとおりです。

$ ./c 
*** __NSAutoreleaseNoPool(): Object 0x100105ec0 of class NSInvocation autoreleased with no pool in place - just leaking 
*** __NSAutoreleaseNoPool(): Object 0x100111300 of class NSCFSet autoreleased with no pool in place - just leaking 
*** __NSAutoreleaseNoPool(): Object 0x100111b60 of class NSCFSet autoreleased with no pool in place - just leaking 
*** __NSAutoreleaseNoPool(): Object 0x100105660 of class NSCFSet autoreleased with no pool in place - just leaking 
performSomeTask NOT on the main thread! 
-- hey howdy 

私たちが見ることができるように、そこにをリークしているNSInvocationNSSetのインスタンスであるが、-performSomeTask:で自動解放文字列がをリークされていない、ので、自動解放プールはその呼び出し操作のために作成されました。

私はそれがNSInvocationOperation(とAppleの枠組み内proballyすべてNSOperationサブクラス)が並行処理プログラミングガイドでは、カスタムNSOperationサブクラスのための示唆と同じように、自分自身の自動解放プールを作成することを前提としても安全だと思います。

+0

iOS 3.xでこれをテストしましたか?これは、ここに記載されているGCDの実装の詳細かもしれません:http://stackoverflow.com/questions/4141123/do-you-need-to-create-an-nsautoreleasepool-within-a-block-in-gcd – Danra

+0

@Danra AFAICT NSOperationQueueはGCDを使用しません。また、上記のコードを '[op start]'を介して同期的に実行するように変更すると、文字列が漏れていることを示すメッセージは表示されません。つまり、 'NSInvocationOperation'がオペレーションの自動解放プールを作成します。 –

+0

@Danra私はMac OS 10.6.6でこの動作をテストしました。 –

関連する問題