这是一个棘手的场景。我一直在研究块并且第一次开始实现它们,我发现自己想要创建一个“复合块”。这是我的代码,粗略地说:
- (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下运行。
提前致谢:)
答案 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
已,则只会返回相同的堆副本。