从我已经设置了NSAutoreleasePool的线程方法返回后,我收到了EXC_BAD_ACCESS错误。失败的地方是致电NSRunLoop。我试图包装一个主要由一个类组成的第三方库(让我们称之为Connection类)及其委托,这样它将同步运行而不是异步运行到客户端类。包装类(称为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的调用将导致在主线程上调用其中一个委托方法。在每个回调方法中,我将变量callBackMethod设置为NO,导致methodA中的while循环退出。在doSomethingImportant返回之后但在调用其中一个委托方法之前发生错误。在调用NSRunLoop时发生EXC_BAD_ACCESS错误。这是堆栈跟踪的一部分:
#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来做正确的事情,但看起来我做错了。但是我不清楚这可能是什么。任何帮助非常感谢!
富
答案 0 :(得分:1)
首先,你确实需要新线程有一个自动释放池,所以不要试图解决这个问题。 : - )
也就是说,这有一些过早发布或代码中过度释放的标志。我会特别注意Connection对象的委托,因为关于保留其委托的对象的规则有点滑。 (Cocoa对象一般不保留他们的代表,但第三方代码可能 - 有时候有充分的理由。)
我现在请你注意Tracking Memory Usage。 MallocDebug和NSZombieEnabled = YES的一些排列应该最终揭开罪魁祸首代码。
但是,一旦你越过这个bug,你可能想要探索Grand Central Dispatch这种事情,而不是滚动你自己的线程...你的代码看起来应该是它应该使用NSCondition或pthread_condition变量严格正确。虽然你可以在当前的硬件上侥幸逃脱,但是这些不同步的共享访问很容易引起一些非常讨厌的竞争。 GCD(AKA libdispatch)提供了一个很多更清洁和更现代的范例,所以如果你要学习一些新的东西,那么很多比pthreads / NSThread /等更好的投资。 : - )