使用调度异步时,我遇到了一个非常奇怪的错误访问错误。我设法将它减少到我的程序中的这段代码。
-(void)buttonTapped:(id)sender {
__block NSArray*foo = nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
//Foo was initially declared here but then moved it outside.
foo = [self someMethod];
[foo retain]; // bad access here. Why ?
dispatch_async(dispatch_get_main_queue(),0) {
// doesnt matter what happens here
}); });
}
-(id)someMethod
{
return [self secondMethod];
}
-(id)secondMethod
{
// was initially returning an autoreleased object from here. Changed it
// to eliminate that as source of the error.
id newThing = [[NSObject alloc] init];
return newThing;
}
代码最初看起来不像这样,但现在就是这样。包括分配一个虚拟NSObject。
如何在调度异步中的调用之间释放foo?我不明白这是怎么可能的。我知道很难说明这是什么,但任何调试建议都会有所帮助。我尝试打开NSZombies,但我没有得到任何僵尸。
答案 0 :(得分:1)
你问:
foo
如何在dispatch_async
内的来电之间释放?
除非someMethod
或secondMethod
本身,否则不应该异步执行某些操作,这可能会导致自动释放池在过渡期间耗尽。
我尝试打开
NSZombies
,但我没有得到任何僵尸。
如果你已经打开僵尸并且你没有得到一个僵尸,那么我怀疑问题在其他地方。坦率地说,我怀疑在为了问题的目的而简化示例代码的过程中,问题的根源被消除了:
其他一些观察/澄清:
您宣布foo
为NSArray
,但之后您将返回NSObject
。我会假设你的意思是NSObject
。{/ p>
您有一行代码说:
dispatch_async(dispatch_get_main_queue(),0) {
我只是假设这是一个错字而你打算:
dispatch_async(dispatch_get_main_queue(), ^{
foo
变量绝对应该位于dispatch_async
块内。对于(a)你没有在块的外部引用块的某个东西({1}}变量没有任何意义。 (b)对于一个块,你是异步调度的。
__block
应返回secondMethod
个对象,因为您显然最初拥有它。 (或者您可能希望将autorelease
和secondMethod
改为以someMethod
开头,以避免混淆,并在您最终迁移到ARC时让自己的生活更轻松。)
如果new
retain
对象,您还需要添加相应的foo
。实际上,您的原始代码示例会返回+1对象,然后再次保留它,将其提升为+2,因此您需要进行两次release
次调用。
无论如何,纠正这些不同的问题,我最终得到以下内容,这不会产生异常:
release
此外,我建议,特别是在使用手动保留和释放(MRR)时,通过静态分析仪(Xcode“产品”菜单上的“分析”)运行它,并确保您有一个干净的健康状况。 (它本来会指出我提到的一些问题。)它并不完美,但它在识别问题方面非常擅长。
但是,简而言之,上面的代码很好,如果您仍然遇到异常,请使用重现异常的工作代码更新您的问题。