Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
ARC中Objective-C中的递归块_Objective C_Instruments_Automatic Ref Counting_Objective C Blocks - Fatal编程技术网

ARC中Objective-C中的递归块

ARC中Objective-C中的递归块,objective-c,instruments,automatic-ref-counting,objective-c-blocks,Objective C,Instruments,Automatic Ref Counting,Objective C Blocks,所以我使用递归块。我知道,要使块递归,它必须在uu block关键字之前,并且必须复制它,以便将其放在堆上。然而,当我这样做时,它显示为仪器中的泄漏。有人知道我为什么或者怎样避开它吗 请注意,在下面的代码中,我引用了许多其他块,但它们都不是递归的 __block NSDecimalNumber *(^ProcessElementStack)(LinkedList *, NSString *) = [^NSDecimalNumber *(LinkedList *cformula, NSString

所以我使用递归块。我知道,要使块递归,它必须在uu 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);
\u块空(^LeakingBlock)(int)=[^(int i){
i++;
若(i<100)泄漏块(i);
}拷贝];
漏块(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);
void(^Log)(int)=^(int i){
NSLog(@“日志子%i”,i);
};
__块空(^LeakingBlock)(int)=[^(int i){
日志(i);
i++;
若(i<100)泄漏块(i);
}拷贝];
漏块(1);
我曾尝试为Log()使用_block关键字,并尝试复制它,但它仍然泄漏。有什么想法吗

更新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);
void(^Log)(int)=^(int i){
NSLog(@“日志子%i”,i);
};
__弱id WeakLogID=Log;
__块空(^LeakingBlock)(int)=[^(int i){
void(^WeakLog)(int)=WeakLogID;
WeakLog(一);
若(i<100)泄漏块(++i);
}拷贝];
漏块(1);

当然有更好的方法吗?

没有进一步的上下文信息,我可以这样说:

您正在泄漏该块,因为您正在复制它,而没有在其他地方释放它。您需要复制它以将其移动到堆中,这没关系。但是你选择的方式并不完全正确

正确的方法是将其存储为某个对象实例变量,复制它,然后在dealloc中释放它。至少,这是一种不泄漏的方法。

Aaron

由于代码似乎是单线程的,为什么要复制块?如果不复制块,就不会有泄漏


安德鲁

好的,我自己找到了答案……但感谢那些试图帮助我的人

如果在递归块中引用/使用其他块,则必须将它们作为弱变量传入。当然,_弱只适用于块指针类型,因此必须首先对它们进行typedef。以下是最终解决方案:

    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);
typedef void(^IntBlock)(int);
IntBlock\uuu弱日志=^(int i){
NSLog(@“日志子%i”,i);
};
__块空(^LeakingBlock)(int)=^(int i){
日志(i);
若(i<100)泄漏块(++i);
};
漏块(1);

上面的代码没有泄漏。

我无法手动释放它。我正在使用ARC(自动参考计数),这阻止了我这样做。块的范围是方法,因此使用iVar是代码气味。该块应该在方法的末尾被释放。是的,你是正确的,代码是单线程的。但我不确定我是否理解这个声明的意义。如果我不复制块,当块尝试递归地访问自身时,我会获得EXC_BAC_访问权限。实际上,我应该澄清:在不复制块的情况下,我会在赋值时获得EXC_BAD_访问权限,而不是当块尝试递归地访问自身时(如果我不使用__块,就会发生这种情况)。我对细节有点不确定,但我相信这是因为该块最初是作为堆栈上的常量对象创建的,而其内部引用的块是同一个常量堆栈块。首先将块复制到堆中,然后将其分配给_块变量,这样它就可以引用if本身的副本,而不是if本身的文本。感谢分享您的研究,我还没有听说必须同时复制块。然而,最近的LLVM似乎在递归调用“捕获此块中的LeakingBlock”时发出警告,很可能导致保留周期。我发现安抚编译器的唯一方法是对块使用一个单独的弱ptr,这与下面的答案有点类似,尽管它非常笨拙,以至于我试图在本地覆盖警告。一旦您尝试了最新的编译器,我很想看看您的效果。@smallduck最初,我使用了
copy
,因为它会导致块从堆栈复制到堆中。有一段时间,它工作得很好,我还得到了编译器的“递归”错误。我从我的代码中删除了
copy
(正如我的答案所反映的那样),它起了作用(而之前我得到的是
EXC\u BAD\u ACCESS
。我猜苹果改变了
\u block
关键字,在堆上而不是堆栈上创建块……但这只是猜测。@smallduck说实话,我已经放弃使用块进行递归。是的,这是可以做到的,但有点笨拙,而且有太多陷阱。这是真的太容易以retain cycles结束(这在递归中可能非常糟糕),并且变得很难读取。因此通常我只使用方法/函数来执行递归。如果不需要,您不需要typedef:
void(^\uu弱日志)(int)=^(inti){…}
@Mattwillding很好。我认为以前的Xcode版本中不适用这种情况。编译器似乎在块方面不断变化。我刚下载了Xcode 4.6,现在它抱怨上面的代码“可能”会导致一个保留周期。我想苹果仍然在计算整个“块”事情是这样的。我似乎在每次修改编译器时都会更改块代码。我在4.6中也有同样的警告,你也可以用
\uu-weak
修改器标记
LeakingBlock
来修复它。