1

我在 .m 文件中声明了一个全局 NSString 变量。当我使用 stringWithFormat 在 .m 文件中的任何位置为其提供字符串值时,该值不会在函数调用之间持续存在。但是,当我使用 stringWithString 执行相同操作时,该值会在整个实现和任何函数调用中持续存在,从而赋予它真正的全局行为。换句话说,stringWithFormat 和 stringWithString 的内存管理在内部有何不同?

为什么在使用 stringWithFormat 时抛出“发送到已释放实例的消息”时 stringWithString 的值仍然存在(在随后使用 NSString 时,在另一个函数中的 NSLog 语句中说,该函数位于使用 stringWithFormat 为 NSString 赋值的函数之后)?当我用 stringWithString 替换它时没有这样的问题。

谢谢!

编辑:我忘了提到是的,当我之后手动保留时,它在 stringWithFormat 的情况下有效。价值持续存在。因此问题。

4

2 回答 2

3

听起来您没有保留该字符串,因此当您稍后尝试访问它时,它已被释放。如果您不熟悉内存管理,请查看 Apple 的内存管理编程指南

-stringWithString:没有中断的原因可能是因为编译器正在对字符串文字进行一些优化;它查看程序并仅存储一个对已定义相同字符串的引用。因此,您的指针将在应用程序的整个生命周期内保持有效。

你不应该依赖这个。您不能保证所有编译器都会进行此优化。当你创建变量时保留它,当你不再需要它时释放它。

于 2011-02-22T12:04:11.180 回答
2

编译器是聪明的,而不是创建几十个不同的 NSString 实例,它们都持有相同的值,他创建了一个无法释放的实例,而所有其他实例只是指向在你的程序中硬编码的 NSString。

而且因为硬编码的 NSString 永远不会被释放,即使在自动释放池释放它之后,你也可以使用它。

这只是涵盖了您错误的内存管理。你绝对不应该依赖这种行为。


编辑。没什么好说的了。您使用 stringWithString:literal 创建的 NSString 将简单地指向文本在内存中的位置。

一个小例子:

NSString *string = @"Foo";
NSLog(@"%@ - %p", string, string);
NSString *string2 = string;
NSLog(@"%@ - %p", string2, string2);
NSString *string3 = [string copy];
NSLog(@"%@ - %p", string3, string3);
NSString *string4 = [string retain];
NSLog(@"%@ - %p", string4, string4);
NSString *string5 = [NSString stringWithString:string];
NSLog(@"%@ - %p", string5, string5);
NSString *string6 = [[NSString alloc] initWithString:string];
NSLog(@"%@ - %p", string6, string6);

你会看到它们都指向同一个地址。

2011-02-22 13:24:41.202 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.204 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.204 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.206 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.206 xxx[40783:207] Foo - 0x74120
2011-02-22 13:24:41.207 xxx[40783:207] Foo - 0x74120

而且它们都永远不会被释放。因此,您可以从代码中的其他方法访问 string5,它仍然指向地址 295740,并且 NSString "Foo" 仍然存在。

但是此时将释放不指向字符串文字的 NSString 对象,并且您将获得错误的访问异常。

您违反了内存管理规则,但如果您只使用字符串文字,您将永远不会注意到它。直到编译器的行为发生变化。

所以做对了,学习正确的内存管理,不要依赖内部。如果您以后需要它们,请保留所有自动释放的对象。即使它们指向字符串文字

于 2011-02-22T12:04:00.330 回答