这会导致 NSString 泄漏吗?

Does this cause leak of NSString?

我是一名 C 程序员,但对 Objective-C 来说还是个新手。我已经多次看到与 NSString 相关的代码:

NSAppleScript* script = [[NSAppleScript alloc] initWithSource: @"<some script code>"];
...
[script release];

上面的代码显式地释放了NSAppleScript对象,但似乎并没有在任何地方释放NSString对象。

我想知道 [script release] 是否会自动完成 NSString 对象的隐式释放工作,所以我将上面的代码更改为以下代码:

NSString* scriptText = @"<some script code>";
NSAppleScript* script = [[NSAppleScript alloc] initWithSource: scriptText];
...
[script release];
//If [script release] has implicitly released scriptText,
//this would cause a repeated release.
[scriptText release];

但是上面的代码结果运行也很好。这是否意味着 [script release] 不会自动释放 NSObject 对象?换句话说,第一节中的代码是否泄漏了 NSString 的释放?

非常简短的回答:没有。你不应该释放 scriptText。 (事实上​​,你不能。)

在ObjC 手动引用计数中,需要遵循基于方法名的规则。如果您调用名称以 allocnew 开头或包含 copy 的方法,则您有责任在对象上调用 releaseautorelease返回给你。此外,如果您在对象上调用 retain,则您有责任调用 releaseautorelease.

根据规则,您调用了 +[NSAppleScript alloc],因此您有责任对返回给您的对象调用 release。您没有调用保留方法来获取 scriptText;您使用了 NSString 文字 (@"...")。所以你不能在上面调用 release 。它不会泄漏。 (如果是,则表示 Apple 代码中存在错误。)

实际工作的方式是 NSString 文字直接存储在二进制文件中,就像在 C 中一样。不需要管理它们,因为它们不直接使用内存。但这与您在手动引用计数下的义务无关。你不应该认为“这是一个字符串文字,所以我不应该对它调用 release”。那根本不是真的。当规则告诉您调用 release 时,您应该调用 release。对恰好是文字的值调用 retain,然后再对其调用 release 是完全正确的。 (这种情况经常发生。您通常不知道您正在使用的 NSString 是否是文字。)

碰巧在 NSString 文字上调用 retainrelease 什么都不做。他们只是忽略了这个电话。非常短的 NSString 对象甚至不存在于内存中。如果它们足够短,数据将直接存储在指针中(称为“标记指针”)。同样,这只是一个实现细节。你的工作是遵守规则,而不是试图猜测系统。

(带有额外 release “有效”的不正确代码的原因是文字 NSStrings 忽略了内存管理调用。代码仍然不正确。也没有承诺过度释放对象会导致在任何情况下都会发生崩溃,当它确实发生崩溃时,它是非常非常常见的,因为它发生在一个随机点,远离错误。对象有待处理的 autorelease 调用是很常见的,所以当池排干时你会崩溃,没有提示你的错误在哪里。)

当然,您应该打开 ARC 并让它为您处理。它做得很好。但无论如何,了解规则还是有帮助的。 ARC 使用相同的基于名称的规则来确定放置保留和释放的位置。这就是它可以与手动内存管理无缝互操作的方式。