编辑2:
没有。建议的答案是关于异步 调用。我想要并且需要同步调用,就像在正常的标准递归调用中一样。
编辑:
同时
__unsafe_unretained void (^unsafe_apply)(UIView *, NSInteger) ;
编译时没有警告或错误,它在运行时失败并在 unsafe_apply 中存储 NULL。
但是这样:
- (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) ;
}
编译没有警告,但更重要的是,实际运行。
但这太丑了!
考虑(为 View 层次结构着色,用于暴露目的...):
- (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 指针变量“apply”在被 block 捕获时未初始化
如果我应用建议的修复:也许你打算使用 __block 'apply'
void (^__block apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
然后我得到:/Users/verec/Projects/solotouch/SoloTouch/BubbleMenu.m:554:13: 在此 block 中强烈捕获“apply”可能会导致保留周期
我尝试了各种方法来篡改代码并摆脱那些警告
__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) ;
谁有更好的解决方案,我可以在 block 内做所有事情,而不是可怕地回补丁,就像我必须在这里做的那样?
最佳答案
您需要捕获一个__block
变量,因为 block 在创建时按值捕获非__block
变量,并且赋值发生在之后 区 block 已创建。
在ARC中,对象指针类型的__block
变量(一般所有变量都是隐式__strong
)被block保留。因此,如果 block 捕获指向自身的 __block
变量,它将创建一个保留循环。解决方案是让它捕获弱引用。在支持 __weak
的操作系统版本中,应使用 __weak
而不是 __unsafe_unretained
。
但是,如果对 block 的唯一引用是一个__weak
变量,则不会有对该 block 的强引用,这意味着它可以被释放。为了使用这个 block ,它必须有一个强引用来保持它。
因此,您需要两个变量,一弱一强。在 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) ;
关于objective-c - ARC 中的递归 block 和保留循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19884403/