NSAutoreleasePool を設定したスレッド メソッドから戻ると、EXC_BAD_ACCESS エラーが発生します。失敗の場所は、NSRunLoop への呼び出しにあります。主にクラス(接続クラスと呼びましょう)とそのデリゲートで構成されるサードパーティライブラリをラップして、クライアントクラスに対して非同期ではなく同期的に動作するようにしようとしています。NFCConnection と呼ばれるラッピング クラスはデリゲート プロトコルに準拠し、NFCConnection のコンストラクターで Connection の setDelegate メソッドに渡されます。
新しいスレッドを作成する方法は次のとおりです。
- (void)methodA {
[NSThread detachNewThreadSelector:@selector(doSomethingImportant)
toTarget:self
withObject:nil];
while (!callBackInvoked) {
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode // Error!
beforeDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
}
}
スレッド メソッド doSomethingImportant は次のようになります。
- (void)doSomethingImportant {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[[Connection instance] somethingImportant];
[pool release];
}
Connection の somethingImportant を呼び出すと、デリゲート メソッドの 1 つがメイン スレッドで呼び出されます。これらのコールバック メソッドのそれぞれで、変数 callBackMethod を NO に設定し、methodA の while ループを終了させます。エラーは、doSomethingImportant が返された後、デリゲート メソッドの 1 つが呼び出される前に発生します。EXC_BAD_ACCESS エラーは、NSRunLoop の呼び出しで発生します。スタック トレースの一部を次に示します。
#0 0x3138cec0 in objc_msgSend
#1 0x000100ac in -[Connection ProcessRx_Api_SomethingImportant:] at Connection.m:621
#2 0x000114fa in +[Connection ProcessRx:] at Connection.m:900
#3 0x00012758 in -[CommHandling ProcessRx:length:] at CommHandling.m:294
#4 0x000126b8 in -[CommHandling stream:handleEvent:] at CommHandling.m:331
#5 0x30a7b958 in -[EAInputStream _streamEventTrigger]
#6 0x30a7be78 in __streamEventTrigger
#7 0x323f53a6 in CFRunLoopRunSpecific
#8 0x323f4c1e in CFRunLoopRunInMode
#9 0x3373c966 in -[NSRunLoop(NSRunLoop) runMode:beforeDate:]
#10 0x0000ae66 in -[NFCConnection methodA:] at NFCConnection.m:137
#11 0x0000bbf2 in -[NFCTestViewController doIt] at NFCTestViewController.m:39
...
これで、エラーの発生をまったく防ぐことができ、doSomethingImportant で自動解放プールの設定を怠ると、ラップされた API が同期的に動作するように見えます。しかし、それを行うと、コンソールに次のように出力されます。
2010-08-09 14:54:49.259 ConnetionTest[3353:652f] *** _NSAutoreleaseNoPool(): Object 0x1928b0 of class __NSCFDate autoreleased with no pool in place - just leaking
Stack: (0x3374ff83 0x33723973 0x3372393f 0x323f78f1 0x3372b913 0x10221 0xc833 0xb045 0x33731acd 0x336dfd15 0x33ad8788)
2010-08-09 14:54:49.272 ConnetionTest[3353:652f] *** _NSAutoreleaseNoPool(): Object 0x18f800 of class NSCFTimer autoreleased with no pool in place - just leaking
Stack: (0x3374ff83 0x33723973 0x3372393f 0x3372b93b 0x10221 0xc833 0xb045 0x33731acd 0x336dfd15 0x33ad8788)
上記のメッセージは、Connection クラスのインスタンスで何かが解放されていないことが原因ですか? 私は NSDate を作成していますが、リリースする必要があるインスタンスではありません。NSTimer と同じことです。
ここで NSAutoreleasePool を設定して正しいことをしようとしていますが、何か間違っているようです。しかし、私はそれが何であるかについての手がかりを持っていません。どんな助けでも大歓迎です!
リッチ