1

我编写了以下代码:

NSString *string = [[NSString alloc] initWithFormat:@"test"];
[string release];

NSLog(@"string lenght = %d", [string length]);
//Why I don't get EXC_BAD_ACCESS at this point?

我应该,它应该被释放。上次发布后,retainCount 应该是 0,为什么不是呢?

PS 我正在使用最新的 XCode。

更新:

NSString *string = [[NSString alloc] initWithFormat:@"test"];

NSLog(@"retainCount before = %d", [string retainCount]);// => 1

[string release];

NSLog(@"retainCount after = %d", [string retainCount]);// => 1 Why!?
4

4 回答 4

4

在这种情况下,框架可能会@"test"NSString *string = [[NSString alloc] initWithFormat:@"test"];. 也就是说,它决定了字面量可以被重用,并在这个上下文中重用它。毕竟,输入匹配输出。

但是,您不应该在程序中依赖这些内部优化——只要坚持引用计数规则和明确定义的行为即可。

更新

大卫的评论使我对此进行了调查。在我测试的系统上,NSString *string = [[NSString alloc] initWithFormat:@"test"];返回一个对象。您的程序向一个应该被释放的对象发送消息,并且不符合不朽字符串状态的条件。

您的程序仍然落入未定义的领域,并且恰好在某些情况下似乎给出了正确的结果,这只是作为实现细节的产物 - 或者仅仅是巧合。正如大卫指出的那样,在发布和日志之间添加“东西”可能会导致string真正被破坏并可能被重用。如果您真的想知道为什么这一切都有效,您可以阅读 objc 运行时源或在运行时的程序集执行时抓取它。有些可能有解释(运行时实现细节),有些纯属巧合。

于 2012-06-15T19:46:30.800 回答
3

更新:

好的。我很累,没有仔细阅读你的问题。

你没有崩溃的原因是纯粹的运气。起初我认为您使用的是initWithString:在这种情况下所有关于字符串文字的答案(包括我原来的答案(如下))都是有效的。


我所说的“纯粹的运气”是什么意思

这样做的原因只是对象已被释放,但您的指针仍指向它曾经所在的位置,并且在您再次读取之前内存没有被覆盖。因此,当您访问从未触及的内存中读取的变量时,这意味着您获得了一个有效的对象。这样做是非常危险的,并且最终导致未来的崩溃!

如果您开始在发布和日志之间创建更多对象,那么其中一个可能会使用与您的字符串相同的内存,然后您在尝试读取旧内存时会崩溃。

它甚至是如此脆弱,以至于连续调用 log 两次会导致崩溃。


原答案:

字符串文字永远不会被释放!

看看这个问题的回答,了解为什么会这样。

这个答案也有很好的解释。

于 2012-06-15T19:55:31.387 回答
3

对已释放对象执行操作是未定义的行为。含义 - 有时你逃脱它,有时它崩溃,有时它在一分钟后在完全不同的位置崩溃,有时十个文件之外的变量被神秘地修改。

要发现这些问题,请使用 NSZombie 技术。查一下。那,还有一些编码纪律。

这一次,你逃脱了,因为释放的内存还没有被任何东西覆盖。string指向的内存仍然包含具有正确长度的字符串对象的字节。一段时间后,会出现其他东西,或者内存地址将不再有效。不知道什么时候会发生这种情况。

nil但是,向对象发送消息是合法的。实际上,这是 Objective C 中定义的行为 - 没有任何反应,返回 0 或 nil。

于 2012-06-15T19:46:22.813 回答
2

一种可能的解释:您多余地动态分配字符串,而不仅仅是使用常量。可能 Cocoa 已经知道这只是浪费内存(如果您没有创建可变字符串),因此它可能会释放分配的对象并返回常量字符串。并且在常量字符串上,释放和保留没有任何效果。

为了证明这一点,值得将返回的指针与常量字符串本身进行比较:

int main()
{
    NSString *s = @"Hello World!";
    NSString *t = [[NSString alloc] initWithFormat:s];

    if (s == t)
        NSLog(@"Strings are the same");
    else
        NSLog(@"Not the same; another instance was allocated");

    return 0;
}
于 2012-06-15T19:46:13.360 回答