代码示例:为什么我在发布NSString对象后仍然可以访问它?

时间:2009-10-07 01:40:55

标签: objective-c cocoa reference-counting

我只是写了一些探索性代码来巩固我对Objective-C的理解,我遇到了这个我不太了解的例子。我定义了这个方法并运行代码:

- (NSString *)stringMethod
{
    NSString *stringPointer = [[NSString alloc] initWithFormat:@"string inside stringPointer"];
    [stringPointer release];
    [stringPointer release];
    NSLog(@"retain count of stringPointer is %i", [stringPointer retainCount]);
    return stringPointer;
}

运行代码并调用此方法后,我注意到一些事情:

  1. 通常情况下,如果我在达到零保留计数后尝试访问被认为已解除分配的内容,则会出现EXC_BAD_ACCESS错误。在这里,我得到了malloc“双重免费”错误。那是为什么?

  2. 无论我添加多少行“[stringPointer release]”,NSLog都会报告保留计数为1.当我添加更多版本时,我会得到更多“双重免费”错误。为什么发布语句不按预期工作?

  3. 虽然我已经过度发布了stringPointer并且我收到了一堆“双重免费”错误,但返回值仍然可以好像没有发生任何事情(我在主代码中有另一个NSLog报告返回值)。该程序继续正常运行。同样,有人可以解释为什么会发生这种情况吗?

  4. 这些例子相当简单,但我试图全面掌握正在发生的事情。谢谢!

3 个答案:

答案 0 :(得分:6)

你得到双重免费错误,因为你发布了两次并导致两个dealloc消息。 = P

请记住,仅仅因为您发布并不意味着其内存地址的数据会立即被销毁。它只被标记为未使用,因此内核知道,在将来的某个时刻,它可以自由地用于另一个数据。在此之前(在您的应用空间中完全不确定),数据将保留在那里。

再次:释放(和dealloc'ing)不需要在字节级别立即销毁数据。它只是内核的标记。

答案 1 :(得分:3)

这里有几件事情要发生。首先,解除对象的释放不一定能清除对象以前占用的任何内存。它只是标志着它是免费的。除非你做了其他导致内存重复使用的内容,否则旧数据就会消失。

在NSString的特定情况下,它是一个类集群,这意味着从alloc / init返回的实际类是NSString的一些具体子类,而不是NSString实例。对于“常量”字符串,这是一个非常轻量级的结构,只保留指向C字符串常量的指针。无论你制作了多少副本,或者释放了多少次,都不会影响指向常量C字符串的指针的有效性。

在这种情况下尝试检查[stringPointer类],以及在可变字符串的情况下,或者实际使用格式字符和参数的格式化字符串。可能所有三个人都会有不同的课程。

答案 2 :(得分:0)

retainCount总是打印一个可能是由优化引起的 - 当释放通知它将被解除分配时,没有理由将retainCount更新为零(因为此时没有人应该对该对象有引用)而不是更新retainCount只是解除分配它。