为什么ARC使用自动释放?

时间:2012-06-25 14:39:35

标签: ios automatic-ref-counting

我在ARC下使用自动释放池运行此代码:

- (NSString*) outName {
    if (!outName) {
        outName = [[NSString alloc] initWithFormat:@"whatever"]; // or stringWithFormat
    }
    return outName;
}

调试器说每次没有池时它会泄漏单个 outName实例。

如果我将代码更改为

,则不会发生这种情况
- (NSString*) outName {
    if (!outName) {
        outName = @"whatever";
    }
    return outName;
}

我不能做(这个例子显然是简化的)。此外,如果我在调用代码中创建一个自动释放池(我想避免),泄漏消息就会消失。

为什么ARC坚持自动释放此对象,该对象保存在strong属性中?更重要的是,我怎样才能避免这种警告?

4 个答案:

答案 0 :(得分:2)

这是一个所有权问题。

让我们先谈谈你自己分配的NSString。 分配对象时,堆中的内存将保留给该对象(除非您将allocWithZone:分配给另一个位置)。保留计数隐式为1并且您拥有该对象,即您在完成后负责释放它。如果要返回指向该对象的指针,即返回该对象,则不会完全放弃确保该对象不泄漏的责任。您无法释放它,因为保留计数将变为0并且该对象将被释放。您自动释放它,确保在运行循环结束时(或更早),对象将被释放并可能被释放。如果返回的对象需要存活更长时间,则调用函数负责保留返回的对象。

没有自动释放池,你会泄漏,因为指定的autoReleasePool为null(记住它的罚款为空,这就是为什么这不只是崩溃而不是泄漏)。

具有固定@“what”的示例不会泄漏,因为编译器会为该字符串保留程序内存,并且-release对它们没有影响。对于一些低值NSNumber也是如此。

正如詹姆斯所说,ARC不会删除保留释放和自动释放概念。

编辑:如何将outName声明为ivar / property?

答案 1 :(得分:0)

Jared's答案很好,但ARC工作方式的一部分是使用命名约定。方法名称outName表示它返回autoreleased值,因此如果有一个de-ARC-ifier,您的最后一行将如下所示:

return [[outName retain] autorelease];

显然这需要一个自动释放池。

这不会发生在你的第二个例子中,因为你正在返回一个常量,所以retain / autorelease会被优化掉。

答案 2 :(得分:0)

当ARC将ivar(或任何对象)返回给调用方法时,必须保证在当前RunLoop完成之前不会释放它。作为程序员,您知道它将永远不会发布,但ARC依赖于算法保证(最佳实践)。 ARC将调用retain] autorelease] ,除非变量指向常量(未使用NARC实例化),因此不会有被释放的风险。

您应避免此警告。您需要修复代码。您可以添加自动释放池。如果您不希望这样做,另一种方法是将使用ivar的逻辑推送到实际持有ivar的对象。

答案 3 :(得分:-1)

很奇怪,我使用了一种非常类似的方法,它没有泄漏。它看起来像这样:

-(NSString *) dataFilePath {

    NSString *appendPath;
    if (isPowerMode==YES) {
        appendPath = kDataFileNamePower;
    } else {
        appendPath = kDataFileNameClassic;
    }

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *documentsDirectory = [paths objectAtIndex:0];
    return [documentsDirectory stringByAppendingPathComponent:appendPath];
}       

所以也许从那里开始,你想要在方法的开头声明一个空的NSString指针并填充并返回它而不是outName。