EDIT2:
没有。建议的答案是关于 async 调用。我想要&需要同步调用,就像在正常的标准递归调用中一样。
编辑:
,而
__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ;
在没有警告或错误的情况下编译,它在运行时失败,并将NULL存储到unsafe_apply。
但是这个:
- (void) applyToView: (UIView *) view {
UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) {
return [UIColor colorWithHue: ((CGFloat) index / 255.0f)
saturation: 0.5f
brightness: 0.5f
alpha: 1.0f] ;
} ;
void (^applyColors) (UIView *, NSInteger index) = ^(UIView * view, NSInteger index) {
view.backgroundColor = colorForIndex(index) ;
} ;
void (^__block recurse_apply)(UIView *, NSInteger) ;
void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
applyColors(view, level) ;
[view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
recurse_apply(subview, 1+level) ;
}] ;
} ;
recurse_apply = apply ;
apply(view, 0) ;
}
在没有警告的情况下编译,但更重要的是,实际运行。
但这太丑了!
考虑(着色视图层次结构,用于公开目的......):
- (void) applyToView: (UIView *) view {
UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) {
return [UIColor colorWithHue: ((CGFloat) (index * 10.0f) / 255.0f)
saturation: 0.5f
brightness: 0.5f
alpha: 1.0f] ;
} ;
void (^applyColors) (UIView *, NSInteger index) = ^(UIView * view, NSInteger index) {
view.backgroundColor = colorForIndex(index) ;
} ;
void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
applyColors(view, level) ;
[view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
apply(subview, 1+level) ;
}] ;
} ;
apply(view, 0) ;
}
我收到了这个警告:
/Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:551:42: Block pointer variable 'apply' is uninitialized when captured by block
如果我应用建议的修正:Maybe you meant to use __block 'apply'
void (^__block apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
然后我得到:/Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:554:13:Capturing 'apply' strongly in this block is likely to lead to a retain cycle
我尝试了各种方法来篡改代码并摆脱这些警告
__weak typeof (apply) wapply = apply ;
if (wapply) {
__strong typeof (wapply) sappy = wapply ;
wapply(subview, 1+level) ;
}
但事情变得更糟,变成了错误。
我最终得到了这个:
__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ;
void (^apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
applyColors(view, level) ;
[view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
unsafe_apply(subview, 1+level) ;
}] ;
} ;
unsafe_apply = apply ;
apply(view, 0) ;
任何人都有一个更好的解决方案,我可以从块内完成所有操作,而不是像我必须在这里做的那样隐藏补丁吗?
答案 0 :(得分:58)
您需要捕获__block
变量,因为块在创建时按值捕获非__block
变量,并且在块创建后发生
在ARC中,块保留了对象指针类型的__block
个变量(通常所有变量都隐含__strong
)。因此,如果块捕获指向自身的__block
变量,则会创建保留周期。解决方案是让它捕获一个弱引用。在支持__weak
的操作系统版本中,应使用__weak
代替__unsafe_unretained
。
但是,如果对块的仅引用是__weak
变量,则不会对该块进行强引用,这意味着它可以被释放。为了使用该块,它必须有一个强大的参考来保持它。
因此,您需要两个变量,一个弱,一个强。在ARC中执行此操作的正确方法是:
__block __weak void (^weak_apply)(UIView *, NSInteger) ;
void (^apply)(UIView *, NSInteger) ;
weak_apply = apply = ^(UIView * view, NSInteger level) {
applyColors(view, level) ;
[view.subviews enumerateObjectsUsingBlock:^(UIView * subview, NSUInteger idx, BOOL *stop) {
weak_apply(subview, 1+level) ;
}] ;
} ;
apply(view, 0) ;
答案 1 :(得分:1)
为了避免ARC警告并建立@newacct的答案,我发现在保留块内设置弱块有效:
//a block definition
typedef void (^CompletionType)(NSDictionary * __nullable response, NSError * __nullable error);
//a block calling itself without the ARC retain warning
__block CompletionType completionBlock = nil;
__block __weak CompletionType weakCompletionBlock = nil;
completionBlock = ^(NSDictionary *response, NSError *error) {
weakCompletionBlock = completionBlock;
weakCompletionBlock();
});
};
答案 2 :(得分:0)
答案是否定的。
我们似乎无法比使用__block限定符做得更好。
__block void(^strawberryFields)();
strawberryFields = ^{ strawberryFields(); };
strawberryFields();
感谢关于块的Bill Bumgarner文章。
编辑:
__block __weak void(^strawberryFields)();
似乎是ARC的首选方式。