2

我按照以下准则编写了一个递归块:

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:方法中,我将完成处理程序添加到数组中:

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

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

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

问题是完成处理程序只被调用一次。该removeObjectForKey:行使块解除分配。如果我取消注释该行,一切正常。我不确定数组是如何最后引用这个块的,因为我添加了 a copy(我相信它正在被优化为 a retain)。

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

  • 通过网络为第一组发送数据
  • 收到回复
  • 调用完成处理程序
  • 在完成处理程序中,为下一组发送数据(这是递归部分)。

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

4

2 回答 2

3

在执行块-performCompletionHandlerForKey:从字典中删除完成处理程序,这意味着处理程序将始终在一次运行后从字典中删除。

相反,将块存储在临时变量中,并在执行块之前将其从字典中删除。

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

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

weakHandler = handler;
[bar asyncOperationWithCompletion:handler];
于 2013-08-05T16:45:29.220 回答
-1

避免保留保留循环的一种流行方法是在定义块之前创建对对象的弱引用,然后在块内创建强引用并将其设置为该弱引用。此方法经常用于避免强烈捕获self块内部:

- (void)someMethod {
    __weak MyType *weakSelf = self;
    [self someMethodWithABlockArg:^{
        MyType *strongSelf = weakSelf;
        [strongSelf someOtherMethod];
    }];
}

在块内创建的强引用可防止在块运行时释放对象。当然,您可以对任何对象类型执行相同的操作。

Edit2:看起来[someBlock copy]确实不错。您是否尝试过在代码上运行分析?当它在块内部被引用时,它可能completion尚未初始化。

于 2013-08-05T15:45:24.253 回答