簡體   English   中英

Objective-C中的遞歸塊在ARC中泄漏

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM