NSString地址问题

Dha*_*ngh 5 objective-c

我正在尝试将地址打印到字符串,但我在第一个NSLog和第二个NSLog中的相同地址获得不同的地址.所以你能告诉我这是怎么回事.它让我很困惑.非常感谢您的努力.

NSString *str1 = [[NSString alloc] init];
NSString *str2 = [[NSString alloc] init];
NSString *str3 = [[NSString alloc] init];

NSLog(@"str1 = %p , str2 = %p, str3 = %p",&str1,&str2,&str3);
NSLog(@"str1 = %p , str2 = %p, str3 = %p",str1,str2,str3);
Run Code Online (Sandbox Code Playgroud)

产量

str1 = 0x7fff565b9c88 , str2 = 0x7fff565b9c80, str3 = 0x7fff565b9c78
str1 = 0x10c0a7060 , str2 = 0x10c0a7060, str3 = 0x10c0a7060
Run Code Online (Sandbox Code Playgroud)

我不明白为什么str1,str2并且str3都指向相同的内存位置.

nhg*_*rif 5

为什么 str1,str2,str3所有居住在不同的内存地址?它们都是不变的字符串.

请参阅bbum的评论:

对......相关利益的一个实施细节(但绝不会使答案无效); [[NSString alloc] initWithString:@"Hello world"]实际上不会在堆上创建一个字符串.它将返回编译器在mach-o文件中放置的__NSCFConstantString(或其所谓的任何内容).这只是一个有趣的细节,因为它不会改变你对所述字符串消费的任何改变; 它应该像任何其他对象一样对待.

强调我的.

这里发生的是当编译器在编译时可以确定不可变NSString对象是什么时,它会以不同的方式创建该字符串.正如bbum所述,最终它是一个实现细节,在编写程序时不必担心.

但这样做的副作用意味着编译器能够使我的程序更高效,因为它能够找到所有这些实例,并使我NSString知道的所有指针都应该保持相同的不可变值.相同的单个内存地址.

我们可以通过以下方式获得相同的结果:

NSString *str1 = [[NSString alloc] init];
NSString *str2 = [NSString new];
NSString *str3 = [[NSString alloc] initWithString:@""];
NSString *str4 = [NSString stringWithString:@""];
NSString *str5 = @"";
Run Code Online (Sandbox Code Playgroud)

这些都是有效的.

但是,如果我们创建另一个字符串:

NSString *str6 = [NSString stringWithFormat:@"%@", @""];
Run Code Online (Sandbox Code Playgroud)

如果我们str6作为指针打印,这将(最有可能......我上次检查)最终得到一个不同的值.

还有其他方法可以生成不可变NSString对象,这些对象在编译时没有像这样进行优化.这里的要点是,如果编译可以在编译时知道字符串将是什么,它将__NSCFConstantString在后台创建一个在内存管理之外的内容,它将指向该单个实例,无论它能做什么.一旦它到达运行时间,如果你直接指向它(str6 = str1),它将只指向其他任何东西.否则,它不会浪费执行时间来确定字符串是否相等.如果一个新的NSString碰巧是相同的并且它没有在编译时发生,它将只由ARC处理.

编译器无法确定str6与其他字符串相同的不可变字符串.这只是构建时间的含义,其他人都以相同的地址结束.

另一个有趣的事情是,你永远不会看到编译器dealloc调用__NSCFConstantString正在为你声明它们的方式声明的变量.因此,编译器不仅可以从内存的角度提高代码的效率,而且还可以删除跟上这些字符串所涉及的所有内存管理代码.