Objective-C将块传递给块

时间:2012-10-07 03:24:35

标签: iphone retain block

这是一个棘手的场景。我一直在研究块并且第一次开始实现它们,我发现自己想要创建一个“复合块”。这是我的代码,粗略地说:

- (void)moveToPosition:(NSInteger)pos withVelocity:(CGFloat)vel onCompletion:(void(^)(BOOL completed))completionBlock
{

    void (^compoundBlock) (BOOL completed) = ^(BOOL completed) {
        [self unlockInteractionFromPullDownMenuTab];
        void(^innerCompletionBlock)(BOOL completed) = completionBlock;
        innerCompletionBlock(completed);
    };

    // Animate
    [UIView animateWithDuration: duration
                     animations: ^void{ [self.pullDownMenu setFrame:newFrame]; }
                     completion: compoundBlock
     ];


}

目标是获取传递给此方法的代码块,向其中添加内容,然后将其传递给动画方法调用。但是,我在线路上访问不好:

innerCompletionBlock(completed);

我认为我的innerCompletionBlock正在取消分配,但我不完全确定原因。根据我的理解,块会复制你向它们抛出的所有内容,包括对self的引用 - 这可以创建保留周期,并且我最近学会了避免。

实际上,我最初尝试过这个:

void (^compoundBlock) (BOOL completed) = ^(BOOL completed) {
    [self unlockInteractionFromPullDownMenuTab];
    completionBlock(completed);
};

但是我得到了错误的访问权限,并且我认为也许复合块没有复制completionBlock,所以我在块中显式声明了一个(块)变量并指定它来尝试让它保留(也许是有点傻,但我在ARC下运行所以我不能做手动保留呼叫。)

无论如何,显然复合块在传递给UIView时会被保留,但我不确定如何在复合块中保留我的onCompletion / innerCompletionBlock,因为我在ARC下运行。

提前致谢:)

2 个答案:

答案 0 :(得分:1)

啊哈,想通了。有点傻,真的。

我曾多次调用方法- (void)moveToPosition:...并将nil传递给completionBlock参数...因为我最后不需要做任何额外的事情动画中只需要在compoundBlock中添加的[self unlockInteractionFromPullDownMenuTab];

有道理,对吧?

...只有在调用块之前检查nil。正如在SO上所讨论的那样elsewhere,“当你执行一个块时,首先测试块是否为零是很重要的”。好吧,我在那里吸取了教训。

此代码有效:

// Compound completion block
void (^compoundBlock) (BOOL completed) = ^(BOOL completed) {
    [self unlockInteractionFromPullDownMenuTab];
    if (completionBlock != nil) {
        completionBlock(completed);
    }
};

答案 1 :(得分:0)

在堆栈上创建块。您需要将completionBlock复制到堆中,以便在尝试运行它时确保它仍然有效。只需将其放在方法的顶部:

completionBlock = [completionBlock copy];

请注意,如果堆上的completionBlock ,则只会返回相同的堆副本。