0

当我测试方法“retainCount”时,我遇到了一个问题,如下所示:

NSString *s_afmt0 = [[NSString alloc] initWithFormat:@""]; //-1
NSString *s_afmt1 = [[NSString alloc] initWithFormat:@"123"]; //1
NSLog(@"s_afmt0:%d", [s_afmt0 retainCount]);
NSLog(@"s_afmt1:%d", [s_afmt1 retainCount]);

结果:s_autf0:-1 s_autf1:1 我不知道为什么?为什么s_afmt0的retainCount是-1,s_autf1的retainCount是1。@""和@"123"有什么区别?谁能解释一下?谢谢

4

2 回答 2

9

您将 retainCount 作为有符号整数打印,而实际上它是无符号整数(NSUInteger格式说明符为%u, not的类型%d)。-1 等价于UINT_MAX,表示对象没有retainCount。很可能 NSString 已经认识到给定的字符串是不可变的,并将指针分配给静态的 @"" 空 NSString,而不是在堆上放置一个。

实际上,您可以使用以下代码来确认这一点:

NSString* str1 = [[NSString alloc] initWithFormat:@""];
NSString* str2 = [[NSString alloc] initWithFormat:@""];

NSLog(@"string1: %p, string2: %p", str1, str2);

上面的代码应该为 str1 和 str2 打印相同的指针地址,证实了我的理论,即 NSString 优化了这个特殊情况,确实如此:

06:46:30.142 StringTest[45214:303] string1: 0x7fff7d8acf90, string2: 0x7fff7d8acf90

所以让我们看看这是否特定于 NSString。应该是这样,否则所有初始化为空字符串的 NSMutableString 对象都将指向同一个内存!

NSMutableString* str1 = [[NSMutableString alloc] initWithFormat:@""];
NSMutableString* str2 = [[NSMutableString alloc] initWithFormat:@""];

NSLog(@"string1: %p, string2: %p", str1, str2);

输出:

06:53:36.688 StringTest[45278:303] string1: 0x10010a850, string2: 0x10010a890

两个不同的内存位置。这样就完成了,Foundation 框架中的一个巧妙的小优化。TIL

编辑:

正如 bbum指出的那样,你永远不应该依赖 retainCount,这是一个例子,如果你这样做,事情可能会出错

于 2012-10-31T03:44:40.680 回答
1

虽然您永远不应该使用retainCount,但您看到的最可能的原因是空字符串 @"" 被编译器视为特殊,因为它是如此常见的文字。

另外,为什么要使用带有字符串文字的字符串格式?我想这只是为了测试目的,但你应该有:

NSString *s_afmt0 = @""; // no need to use stringWithFormat here
于 2012-10-31T03:46:56.197 回答