Objective-C中带有块的递归

3

在我的iOS应用程序中,当进行涉及Objective-C块的递归时,我收到EXC_BAD_ACCESS信号。以下是简化的代码:

- (void)problematicMethod:(FriendInfo*)friendInfo onComplete:(void(^)(NSString*))onComplete1 {

[self doSomethingWithFriend:friendInfo onComplete:^(Response* response) {
    switch (response.status) {
        case IS_OK:
            onComplete1(message);
            break;

        case ISNT_OK:
            // Recursively calls the method until a different response is received 
            [self problematicMethod:friendInfo onComplete:onComplete1];
            break;          

        default:
            break;
    }
}];
}

所以基本上,这个简化版本中的problematicMethod调用doSomethingWithFriend:onComplete:。当该方法完成(onComplete)并且一切正常时,原始的onComplete1块就会被调用,这很好地工作。但是如果出现问题,需要再次调用problematicMethod(递归部分),当第一次发生时,我立即收到EXC_BAD_ACCESS信号。任何形式的帮助将不胜感激。

坦白地说,我不知道立即EXC_BAD_ACCESS的来源。顺便说一句,如果您提供有关异常的更多信息将会很有帮助。调试器对此有何说法?无论如何,如果您怀疑递归方法是导致EXC_BAD_ACCESS的原因,为什么不使用performSelector:withObject:afterDelay:来调用problematicMethod呢?withObject可能为空,afterDelay甚至可以为0。 - Hermann Klecker
@HermannKlecker 实际上,调试器已经无法提供更多信息了。EXC_BAD_ACCESS 错误可能会在第一次从 ISNT_OK 调用 [self problem...] 方法时发生,也可能是因为读取了不正确的数据(例如 NSArray 变量指向 NSConcreteData 数据)而在第二次进入该方法时发生。 - Misa
越看,我越确定访问数据时使用了错误的内存位置。我尝试使用[block copy]复制每个块,并且泄漏内存(没有自动释放),但是都没有成功。 - Misa
可能我们需要更多的代码 - 块内有什么代码?您还应该尝试调试 - 在那里设置断点并检查应用程序在哪个确切的调用上访问了错误数据。 - Sulthan
2个回答

2

你是如何创建你的代码块的?记住你必须将它从堆栈移动到堆上。

例如:

 void(^onCompleteBlock)(NSString*) = [[^(NSString* param) {
  //...代码块
}] copy] autorelease];

[self problematicMethod:friendInfo onCompleteBlock];


我尝试了这个方法,虽然看起来是完美的解决方案,但它却不起作用。 - Misa
这不是正确的。调用代码不需要复制它,因为它没有存储在任何地方。 - newacct
@newacct 块是在堆栈上创建的。复制块会将其从堆栈移动到堆中。当块被传递给某个响应处理程序并在未来的某个未知时间使用时,我认为这在这种情况下非常重要。 - Sulthan
@Sulthan:是的,但谁说它会在未来某个未知的时间使用?Objective-C中的内存管理完全是本地的。一个方法不需要关心其他方法在做什么。如果被调用的方法将块存储在某个地方,那么负责复制它的是该方法而不是调用者创建块。从调用者的角度来看,无论它调用一个立即使用块的方法还是将其存储以备将来使用,都没有区别。 - newacct
@newacct,如果你在problematicMethod的第一行或者调用它之前加上这段代码都没关系(但我同意最好放在方法内部)。这段代码只需要存在于某个地方即可。问题中没有展示代码,所以我假设它必须在调用之前被调用。 - Sulthan
1
@Sulthan:但是他展示的problematicMethod:onComplete:中没有任何代码将块存储在变量中以供以后使用。它所做的就是执行它或将其传递到更深层次的调用中。如果这就是它所做的,那么它不需要复制它。我们不知道doSomethingWithFriend:onComplete:会做什么;如果它需要存储其参数块以供以后使用,则必须复制它(而不是我们);并且复制它将自动复制onComplete1,因为它是被该块捕获的块。因此,在problematicMethod:onComplete:中不应该有任何复制。 - newacct

0
如果响应状态值不是ISNT_OK,您永远不会停止递归调用该函数。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接