Objective c 圆弧中的递归块和保留循环
编辑2: 不是。建议的答案是关于异步调用。我需要同步调用,就像在普通的、标准的递归调用中一样 编辑: 当 编译时没有警告或错误,它在运行时失败,NULL存储在不安全的应用程序中 然而,这:Objective c 圆弧中的递归块和保留循环,objective-c,recursion,automatic-ref-counting,objective-c-blocks,retain-cycle,Objective C,Recursion,Automatic Ref Counting,Objective C Blocks,Retain Cycle,编辑2: 不是。建议的答案是关于异步调用。我需要同步调用,就像在普通的、标准的递归调用中一样 编辑: 当 编译时没有警告或错误,它在运行时失败,NULL存储在不安全的应用程序中 然而,这: - (void) applyToView: (UIView *) view { UIColor * (^colorForIndex)(NSInteger) = ^(NSInteger index) { return [UIColor colorWithHue: ((CGFloat)
- (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) ;
}
编译时没有警告,但更重要的是,实际运行
但是这太难看了
考虑(为视图层次着色,用于显示目的…): 我得到这个警告: /Users/verec/Projects/solotouch/solotouch/BubbleMenu.m:551:42:
块指针变量“apply”在被块捕获时未初始化
如果我应用了建议的修复:也许你想使用u块“apply”
void (^__block apply)(UIView *, NSInteger) = ^(UIView * view, NSInteger level) {
然后我得到:/Users/verec/Projects/solotouch/solotouch/BubbleMenu.m:554:13:在这个块中强烈地捕获“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 void(^strawberryFields)();
strawberryFields = ^{ strawberryFields(); };
strawberryFields();
感谢关于积木的文章
编辑:
似乎是ARC下的首选方式。您需要捕获一个\u块
变量,因为块在创建时按值捕获非\u块
变量,并且赋值在创建块后发生
在ARC中,对象指针类型的\u块
变量(通常所有变量都隐式地\u strong
)由块保留。因此,如果块捕获指向自身的\u块
变量,它将创建一个保留循环。解决方案是让它捕获弱引用。在支持\uuu弱
的操作系统版本中,应使用\uu弱
而不是\uu不安全的
但是,如果对块的唯一引用是\uu弱
变量,则不会有对块的强引用,这意味着它可以被释放。为了使用块,它必须有一个强大的参考,以保持其周围
因此,您需要两个变量,一个弱变量和一个强变量。在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) ;
为了避免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();
});
};
像我的编辑?但必须支持补丁确实很难看,而且容易出错。是否有一些正常的、标准的方法来使用递归块?特别是可能的重复,请参见否!提到的问题是关于异步调用的。我需要常规的、普通的、标准的递归调用。不涉及线程。该解决方案适用于任何递归块。你试过了吗?你是认真的吗?您所指的“解决方案”有两种方法,20多行代码,并且是异步的!我已经很难过,我自己的版本有3行不必要的行,你会建议我添加更多的混乱,而结果取决于GCD???这段代码早于ARC;从那时起,\u块
的效果发生了变化,在不使用\u弱
的情况下使用它会创建一个保留周期:\u块\u弱
得到警告将块文字赋值给弱变量;对象将在Xcode 5下的赋值`后释放。。。。所以这似乎也不是正确的答案???分两步进行:\u弱空(^weak\u block)()
后跟u块void(^strong_u块)(=^(){if(无论什么)弱_u块();}
,最后添加:弱块=强块
在strong_block
的主体之后。当我使用最新版本的Xcode尝试此操作时,编译器会用一个警告标记它:“将块文字赋值给弱变量;赋值后将释放对象”。由于您的方法正是围绕这一点工作的,所以我认为忽略警告是安全的。你知道如何关闭它吗?@Drux:更改了分配顺序我已经用XCode 6测试过了,但是如果我在块中添加分配,内存将不会被释放:|但是completionBlock
是一个强持有对象,它本身有一个对completionBlock
的强持有引用。因此,您得到了一个保留周期,这与您消除了所有提及的weakCompletionBlock
完全相同。
__block __weak void(^strawberryFields)();
__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) ;
//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();
});
};