2

这是一个有点棘手的场景。我一直在研究积木并第一次开始实施它们,我发现自己想创建一个“复合积木”。这是我的代码,大致如下:

- (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 正在被释放,但我不完全确定为什么。据我了解,块会复制你扔给它们的所有内容,包括对自我的引用——这会产生保留循环,而我最近学会了避免这种情况。

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

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

但是我得到了错误的访问,我想也许compoundBlock没有复制completionBlock,所以我在块内显式声明了一个(块)变量并分配它以试图让它保留(也许有点傻,但我在 ARC 下运行,所以我不能手动保留调用)。

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

提前致谢 :)

4

2 回答 2

1

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

有很多次我调用方法- (void)moveToPosition:...并传递nilcompletionBlock参数......因为我不需要在动画结束时做任何额外的事情,只想要[self unlockInteractionFromPullDownMenuTab];在复合块中添加的内容。

有道理,对吧?

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

此代码有效:

// Compound completion block
void (^compoundBlock) (BOOL completed) = ^(BOOL completed) {
    [self unlockInteractionFromPullDownMenuTab];
    if (completionBlock != nil) {
        completionBlock(completed);
    }
};
于 2012-10-07T03:36:56.193 回答
0

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

completionBlock = [completionBlock copy];

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

于 2012-10-07T03:32:24.247 回答