【问题标题】:Objective-C passing a block into a blockObjective-C 将块传递到块中
【发布时间】:2012-09-27 18:26:31
【问题描述】:

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

- (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 正在被释放,但我不完全确定原因。据我了解,blocks 会复制你扔给他们的所有东西,包括对 self 的引用——这会产生保留循环,而我最近学会了避免这种情况。

其实我最初是这样尝试的:

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

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

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

提前致谢:)

【问题讨论】:

    标签: iphone retain block


    【解决方案1】:

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

    completionBlock = [completionBlock copy];
    

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

    【讨论】:

    • 嗯...感谢您的快速回答。我有一个问题:在 ARC 下是否仍然需要复制块? (似乎不是。)为了争论,如果 not 在 ARC 下运行,我将如何在上面的示例中的两个块上调用 copy?只在方法顶部的completionBlock 上一次,而不是compoundBlock,因为它本身会被 UIView 动画调用在内部复制?谢谢。
    • 如果不在 ARC 下,每个 copy 必须由 releaseautorelease 平衡。在很多情况下,没有必要在 ARC 下 copy 一个块,但仍然有必要的情况,所以我倾向于预防性地这样做。
    • 这不是真的。他不需要在给出的示例中,在 MRC 或 ARC 中显式复制块 completionBlock。该方法不存储completionBlock 以供以后在任何地方使用,除非被另一个块compoundBlock 捕获。当(如果)compoundBlock 被复制时,它将自动复制completionBlock
    【解决方案2】:

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

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

    有道理,对吧?

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

    此代码有效:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多