ARC中的Objective-C泄漏中的递归块 [英] Recursive Blocks in Objective-C leaking in ARC
问题描述
所以我正在使用递归块.我了解要递归的块,必须在其前面加上__block关键字,并且必须将其复制以便将其放在堆中.但是,当我这样做时,它在Instruments中显示为泄漏.有人知道我为什么或如何解决这个问题吗?
So I'm using recursive blocks. I understand that for a block to be recursive it needs to be preceded by the __block keyword, and it must be copied so it can be put on the heap. However, when I do this, it is showing up as a leak in Instruments. Does anybody know why or how I can get around it?
请注意下面的代码中,我引用了很多其他块,但是它们都不是递归的.
Please note in the code below I've got references to a lot of other blocks, but none of them are recursive.
__block NSDecimalNumber *(^ProcessElementStack)(LinkedList *, NSString *) = [^NSDecimalNumber *(LinkedList *cformula, NSString *function){
LinkedList *list = [[LinkedList alloc] init];
NSDictionary *dict;
FormulaType type;
while (cformula.count > 0) {
dict = cformula.pop;
type = [[dict objectForKey:@"type"] intValue];
if (type == formulaOperandOpenParen || type == formulaListOperand || type == formulaOpenParen) [list add:ProcessElementStack(cformula, [dict objectForKey:@"name"])];
else if (type == formulaField || type == formulaConstant) [list add:NumberForDict(dict)];
else if (type == formulaOperand) [list add:[dict objectForKey:@"name"]];
else if (type == formulaCloseParen) {
if (function){
if ([function isEqualToString:@"AVG("]) return Average(list);
if ([function isEqualToString:@"MIN("]) return Minimum(list);
if ([function isEqualToString:@"MAX("]) return Maximum(list);
if ([function isEqualToString:@"SQRT("]) return SquareRoot(list);
if ([function isEqualToString:@"ABS("]) return EvaluateStack(list).absoluteValue;
return EvaluateStack(list);
} else break;
}
}
return EvaluateStack(list);
} copy];
NSDecimalNumber *number = ProcessElementStack([formula copy], nil);
更新 因此,在我自己的研究中,我发现问题显然与该模块使用的其他模块的引用有关.如果我做这样简单的事情,它不会泄漏:
UPDATE So in my own research I've discovered that the problem apparently does have to do with the references to the other blocks this block uses. If I do something simple like this, it doesn't leak:
__block void (^LeakingBlock)(int) = [^(int i){
i++;
if (i < 100) LeakingBlock(i);
} copy];
LeakingBlock(1);
但是,如果我在其中添加另一个块,则会泄漏:
However, if I add a another block in this, it does leak:
void (^Log)(int) = ^(int i){
NSLog(@"log sub %i", i);
};
__block void (^LeakingBlock)(int) = [^(int i){
Log(i);
i++;
if (i < 100) LeakingBlock(i);
} copy];
LeakingBlock(1);
我已经尝试将__block关键字用于Log(),还尝试复制它,但是它仍然泄漏.有什么想法吗?
I've tried using the __block keyword for Log() and also tried copying it, but it still leaks. Any ideas?
更新2 我找到了一种防止泄漏的方法,但是有点麻烦.如果我将传入的块转换为弱ID,然后将弱ID转换回为块类型,则可以防止泄漏.
UPDATE 2 I found a way to prevent the leak, but it's a bit onerous. If I convert the passed in block to a weak id, and then cast the weak id back into a the block type, I can prevent the leak.
void (^Log)(int) = ^(int i){
NSLog(@"log sub %i", i);
};
__weak id WeakLogID = Log;
__block void (^LeakingBlock)(int) = [^(int i){
void (^WeakLog)(int) = WeakLogID;
WeakLog(i);
if (i < 100) LeakingBlock(++i);
} copy];
LeakingBlock(1);
肯定有更好的方法吗?
推荐答案
好吧,我自己找到了答案...但是要感谢那些尝试提供帮助的人.
Ok, I found the answer on my own...but thanks to those who tried to help.
如果要在递归块中引用/使用其他块,则必须将它们作为弱变量传递.当然,__weak仅适用于块指针类型,因此必须首先对它们进行typedef.这是最终的解决方案:
If you're referencing/using other blocks in a recursive block, you must pass them in as weak variables. Of course, __weak only applies to block pointer types, so you must typedef them first. Here's the final solution:
typedef void (^IntBlock)(int);
IntBlock __weak Log = ^(int i){
NSLog(@"log sub %i", i);
};
__block void (^LeakingBlock)(int) = ^(int i){
Log(i);
if (i < 100) LeakingBlock(++i);
};
LeakingBlock(1);
上面的代码没有泄漏.
这篇关于ARC中的Objective-C泄漏中的递归块的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!