递归块被释放得太早 [英] Recursive block gets deallocated too early

查看:89
本文介绍了递归块被释放得太早的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已按照这些准则编写了一个递归块:

I have written a recursive block following these guidelines:

NSMutableArray *groups = [NSMutableArray arrayWithArray:@[@"group1", @"group2", @"group3", @"group4"];

__block CommunicationCompletionHandler completion = [^{
    [groups removeObjectAtIndex:0];

    if ([groups count] > 0) {
        // This will send some information to the network, and calls the completion handler when it receives a response
        [mySocket saveGroup:groups[0] completion:completion];
    }
} copy]; // Removing copy here doesn't work either

[mySocket saveGroup:groups[0] completion:completion];

saveGroup:completion:方法中,我将完成处理程序添加到数组中:

In the saveGroup:completion: method, I add the completion handler to an array:

self.completionHandlers[SaveGroupCompletionHandlerKey] = [completion copy];

当我收到响应时,我调用以下方法(在这种情况下,keySaveGroupCompletionHandlerKey):

And when I receive a response, I call the following method (key is in this case SaveGroupCompletionHandlerKey):

- (void)performCompletionHandlerForKey:(NSString *)key {
    if (self.completionHandlers[key]) {
        ((CommunicationCompletionHandler)self.completionHandlers[key])();
        [self.completionHandlers removeObjectForKey:key];
    }
}

问题在于完成处理程序仅被调用一次. removeObjectForKey:行使该块解除分配.如果我取消注释该行,则一切正常.我不确定数组如何最后引用此块,因为我添加了copy(我认为它已被优化为retain).

The problem is that the completion handler only gets called once. The removeObjectForKey: line makes the block deallocate. If I uncomment that line, everything works fine. I'm not sure how the array has the last reference to this block, since I add a copy (which I believe is being optimized to a retain).

为清楚起见,该应用程序的流程为:

For clarity, the flow of the app is:

  • 通过网络发送第一组数据
  • 接收响应
  • 呼叫完成处理程序
  • 在完成处理程序中,为下一组发送数据(这是递归部分).

这里有谁能指出我做错了什么?

Anybody here who can point out what I'm doing wrong?

推荐答案

-performCompletionHandlerForKey:中,在执行该块之后,您将从字典中删除完成处理程序,这意味着该处理程序将始终被删除.从字典运行一遍后.

In -performCompletionHandlerForKey: you remove the completion handler from your dictionary after executing the block, which means that the handler will always be removed from the dictionary after one run.

相反,将块存储在临时变量中,然后在执行该块之前将其从字典中删除.

Instead, store the block in a temporary variable and remove it from the dictionary before executing the block.

顺便说一句,删除弱引用的建议是错误的.现在编写代码,您的块将永远不会被释放.典型的块递归模式是这样的:

By the way, the advice to remove the weak reference is wrong. As your code is written now, your block will never be deallocated. The typical block recursion pattern is this:

__weak __block MyBlock weakHandler;
MyBlock handler = ^ { 
    if (foo) {
        MyBlock strongHandler = weakHandler;
        [bar asyncOperationWithCompletion:strongHandler];
    }
};

weakHandler = handler;
[bar asyncOperationWithCompletion:handler];

这篇关于递归块被释放得太早的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆