我正在尝试向朋友解释iOS上的内存管理,我向他展示了错误的代码。但是,当我启动应用程序时,它正在工作,我不知道为什么。 这是片段:
NSString *myString = [[NSString alloc] initWithString:@"myString"];
[myString release];
NSLog(@"%@",myString);
我不明白为什么我的NSLog正在工作...... 你有解释吗?
谢谢!
答案 0 :(得分:3)
关于你的例子,有两点需要注意。
正如MByD所解释的那样,访问已被解除分配的对象是未定义的行为。它可能会或可能不会使程序崩溃 - 这取决于分配给该对象的内存是否已被重用以及放在那里的内存。在某些情况下,内存尚未被重用(并且您可能认为该对象仍处于活动状态但该对象实际上是 ghost对象),在其他情况下,内存可能已被另一个重用Objective-C对象(程序不会崩溃,但你会看到一个不同的对象),而在其他情况下,内存可能已经被不是Objective-C对象的东西重用(在这种情况下程序很可能 - 但不是必然 - 崩溃)。
您的字符串对象是一个常量字符串。正如this question及其注释的答案中所解释的那样,永远不会释放常量字符串。当您发送-[NSString initWithString:]
传递常量字符串作为参数时,Cocoa返回原始常量字符串,因此您的代码实际上与NSString *myString = @"myString";
相同。这是一个内部Cocoa实现细节。生产代码应始终考虑+alloc
返回的对象(通常是后续的-init
)由调用者拥有,应该在调用者不再对它们感兴趣时释放,并且不会释放后可以使用。
为了实验,请尝试以下代码:
#import <Foundation/Foundation.h>
#include <stdio.h>
int main(void) {
[NSAutoreleasePool new];
NSString *s1 = [[NSString alloc] initWithString:@"myString"];
NSString *s2 = [[NSString alloc] initWithString:@"myString"];
NSString *s3 = [[NSString alloc] initWithString:@"myString"];
NSString *s4 = [[NSString alloc] initWithString:@"myString"];
printf("s1 = %p\n", s1);
printf("s2 = %p\n", s2);
printf("s3 = %p\n", s3);
printf("s4 = %p\n", s4);
[s1 release];
[s2 release];
[s3 release];
[s4 release];
return 0;
}
从概念上讲,s1
,s2
,s3
,s4
应该是不同的对象。但是,通过运行此程序,您可以看到它们实际上是同一个对象(它们具有相同的地址):
$ ./a.out
s1 = 0x10080b090
s2 = 0x10080b090
s3 = 0x10080b090
s4 = 0x10080b090
答案 1 :(得分:2)
这是一种未定义的行为。您不能访问此字符串,但它可能可用。