NSString长度和retainCount。需要澄清。

4

根据以下代码,请提供建议。

NSString *str= [[NSString alloc] initWithString:@"Hello world"];   

NSLog(@"Length: %lu\n", [str length]);              // 11
NSLog(@"Retain count is %lu\n", [str retainCount]); //1152921504606846975

[str release];

NSLog(@"%lu\n", [str length]);                      // 11
NSLog(@"Retain count is %lu\n", [str retainCount]); //1152921504606846975
  1. 最初我想知道为什么数字这么大,但后来看到了一个解释帖子。我改问这个问题...为什么当我使用%d%lu时,这个数字会大幅变化? 最初我使用的是%d,但出现了一个警告,指出“转换规定类型为int,但参数类型为NSUInteger(也称unsigned long)。修复方法是将%d更改为%lu”。

  2. 为什么保留计数没有减少? 在str被发送release后,大数字仍然不变

  3. 为什么在str被发送release后,我仍然能够访问它?

2个回答

8
这可能是一个难以接受的答案,但这是您应该做的:
  1. 不要担心它。(关于%d/%lu,这些说明符只期望不同的数据类型,%d(int)与%lu(unsigned long)具有更小且不同的范围)
  2. 不要担心它。
  3. 不要这样做,特别是不要依赖它。
这可能是因为您从一个常量字符串(@"Hello world")开始,当您调用release时内存没有被释放,retainCount很大。但是,如果您必须关心retainCount,那么您正在错误地使用它。 您在正确的位置释放了字符串,这才是最重要的 - 永远不要尝试在以后使用它。

我所读有关Objective-C中保留计数的所有内容都让我得出同样的结论。别担心它。 - iandotkelly
很快我们就会有ARC,然后我们就能看到下一个难度级别是什么了。 - Abizern
下一个难度级别将是在头脑中理解对象图 :) - jtbandes
1
@jtbandes - 如果这样的话,就会有很多问题询问如何修复Xcode和LLVM会抛出的所有编译器错误。 - Abizern
@Abizern:是的,就像“我为什么不能调用-release?!1!” - jtbandes

0
最终,行为由NSString的实现定义 - 只需在每种情况下正确使用retain/release即可保证安全。
可能发生的情况是:NSString字面量是不朽的。你可以写while (1) { [@"String" release]; }而没有任何问题。
你调用的复制构造函数可能会返回指向字符串字面量的指针。伪代码如下:
- (id)initWithString:(NSString *)str
{
    self = [super init];
    if (self != nil) {
        if ([str _isStringLiteral] || [str _isImmutable]) {
            [self release];
            return [str retain];
        }
        ...
}

在这种情况下,当通过[[NSString alloc] initWithString:stringLiteral]传递时,您将返回指向字符串字面量的指针。由于对不朽的字符串字面量发送release不起作用,因此您可以看到为什么在假定已释放对象后它仍然是一个有效的对象。
永远不要依赖这样的细节/优化,只需使用正常的生命周期和引用计数,您就会没问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接