没有明确调用Objective-C版本

时间:2011-04-12 14:08:08

标签: iphone objective-c cocoa ios

NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    

NSString * str = [[NSString alloc] initWithString:@"test"];
[str release];
int i = 999999999;
while(i-- > 0) {}
NSLog(@"%@", str);
[pool drain];

输出:测试

为什么release无效? 如何立即从内存中删除对象?

Xcode 4.0版iPhone应用程序

<小时/> 的〜解决〜

感谢所有人的回答。 我有很多关于这个问题的有用信息。我将使用NSString * str = @“text”而不是NSString * str = [[NSString alloc] initWithString:@“text”];

我知道发布只是“标记”记忆“愿意被释放”,但不能立即释放它

5 个答案:

答案 0 :(得分:6)

发布确实有效,但您尝试做的事情有未定义的行为,并且在使用NSString和文字时,您可能也会遇到不同的行为。发生的事情是,虽然您的对象被释放,但该位置的内存可以回收并且没有更改,当它打印时它仍然有效。由于它是一个NSString,因此不一定要发送描述消息,这就是为什么你没有因为尝试发送一个解除分配的对象而得到异常。

This question有一些关于NSString和NSLog的好信息。

答案 1 :(得分:6)

确实有效。您已放弃该对象的所有权,并且当系统确定它不再拥有时,系统将标记为可供系统重用。如果您是该字符串的唯一所有者,那可能会立即发生。如果字符串的创建导致它在内部自动释放,则可能会在稍后的某个时间点发生。或者,正如Dave DeLong指出的那样,系统可能会将其优化为一个永不释放的对象。

在您的情况下,它被优化为一个常量字符串,该字符串将在程序的生命周期中存在。如果您使用的是NSMutableString而不是NSString,您会看到可能不会崩溃的时髦行为,但不会打印您所期望的内容。 (有关示例,请参阅this question。)

如果您使用的是NSArray,那么当您调用release 将被取消分配,但您仍然会看到您的NSLog示例正常工作,直到您分配了其他一些宾语。释放只是将内存标记为可重用;它实际上并没有清除它。因此,如果您将数组传递给NSLog,则该内存尚未更改,因此仍可正确打印。

然而,所有这一切的关键点是要认识到调用release不一定会导致对象被释放。它可能因任何原因而继续存在。但是一旦你打电话给release,你就放弃了对象的所有权。如果你在那之后继续使用它,系统可以自由地做各种奇怪的事情,如图所示。

答案 2 :(得分:4)

当你这样做时:

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

这将优化为:

NSString * str = @"test";

你不能release一个常量字符串,因为它被硬编码到应用程序二进制文件中。

证明:

NSString *s = [NSString alloc];
NSLog(@"%p", s);
s = [s initWithString:@"foo"];
NSLog(@"%p", s);
s = @"foo";
NSLog(@"%p", s);

日志:

2011-04-12 10:17:45.591 EmptyFoundation[6679:a0f] 0x100116370
2011-04-12 10:17:45.599 EmptyFoundation[6679:a0f] 0x100009270
2011-04-12 10:17:45.604 EmptyFoundation[6679:a0f] 0x100009270

您可以看到+alloc的结果与-initWithString:的结果不同-initWithString:的结果等同于常量字符串。基本上,-initWithString:说“啊哈,我将成为一个不可变的字符串,我将被赋予一个不可变的字符串!我可以采取一个捷径,摧毁自己,并返回参数,一切都将仍然工作相同“

答案 3 :(得分:1)

您在NSLog()中使用了错误的指针。在这种情况下,你碰巧变得幸运,但你应该期望这样的代码在其他方面崩溃或失败。

答案 4 :(得分:0)

无需删除内存块,这将耗尽不需要的周期。 当分配新对象占用该内存块时,将覆盖内存。