[英]Recursive Blocks in Objective-C leaking in ARC
所以我正在使用遞歸塊。 我理解,對於要遞歸的塊,它需要以__block關鍵字開頭,並且必須將其復制,以便將其放在堆上。 但是,當我這樣做時,它顯示為儀器中的泄漏。 有誰知道為什么或如何繞過它?
請注意,在下面的代碼中,我已經引用了許多其他塊,但它們都不是遞歸的。
__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);
更新因此,在我自己的研究中,我發現問題顯然與該塊使用的其他塊的引用有關。 如果我做這樣簡單的事情,它不會泄漏:
__block void (^LeakingBlock)(int) = [^(int i){
i++;
if (i < 100) LeakingBlock(i);
} copy];
LeakingBlock(1);
但是,如果我在其中添加另一個塊,它會泄漏:
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()並嘗試復制它,但它仍然泄漏。 有任何想法嗎?
更新2我找到了一種防止泄漏的方法,但這有點麻煩。 如果我將傳入的塊轉換為弱id,然后將弱id轉換回塊類型,我可以防止泄漏。
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);
當然有更好的方法嗎?
好吧,我自己找到了答案......但感謝那些試圖提供幫助的人。
如果您在遞歸塊中引用/使用其他塊,則必須將它們作為弱變量傳遞。 當然,__ weak僅適用於塊指針類型,因此您必須先鍵入它們。 這是最終的解決方案:
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);
上面的代碼不泄漏。
亞倫
由於您的代碼似乎是單線程的,為什么要復制塊? 如果您不復制塊,則沒有泄漏。
安德魯
沒有進一步的背景信息,我可以這樣說:
您正在泄漏該塊,因為您正在復制它而不是將其釋放到其他位置。 您需要復制它以將其移動到堆,這沒關系。 但你選擇的方式並不完全正常。
一個正確的方法是將它存儲為一些對象實例變量,復制它,然后在dealloc中釋放它。 至少,這是一種不泄漏的方法。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.