为什么解引用NSString指针是不必要的?

7
在这个例子中
NSString *message = @"Hello";
message = @"World";

如果消息只是一个指针,为什么我不需要像在C语言中一样明确地说明现在message中的内容等于字符串*message = @"World";呢?

4
因为 @"World" 给出了字符串字面量的地址,所以 message=&... - Anoop Vaidya
1
@"Hello" 的概念上是 [[[NSString alloc] initWithUtf8String:"Hello"]] autorelease] 的一种捷径。 - Hot Licks
1
因为@"World"也是一个指针? ;) - Nicolas Miari
1个回答

14

声明

以下讨论概括了为什么在Objective-C中永远不要对指向对象的指针取消引用。然而,关于NSString字面量的特定情况,实际情况并非如此。虽然下面描述的结构仍然正确且可能起作用,但实际发生的是,在编译时分配字符串字面量的空间,并返回其地址。这对于字符串字面量是正确的,因为它们是不可变和恒定的。因此,出于效率考虑,每个字面量只被分配一次。

事实上

NSString * a = @"Hello";
NSString * b = @"Hello";
NSLog(@"%@ %p", a, a); // Hello 0x1f4958
NSLog(@"%@ %p", b, b); // Hello 0x1f4958

原始回答

因为它将被翻译成其他语言。

message = [[NSString alloc] initWithUTF8String:"Hello"]];

这将归结为

message = objc_msgSend(objc_msgSend(objc_getClass("NSString"), @selector(alloc)), @selector(initWithUTF8String:), "Hello");

现在,如果我们看一下 objc_msgSend 的签名

id objc_msgSend(id theReceiver, SEL theSelector, ...)

我们看到这个方法返回一个id类型,在Objective-C中,id是对象类型。但是id实际上是如何定义的呢?

typedef struct objc_object {
    Class isa;
} *id;

id被定义为指向objc_object结构体的指针。

因此,最终@"string"将被翻译成函数调用,该函数将产生一个指向对象的指针(也就是一个objc_object结构体),这正是你需要分配给message的内容。

总之,你分配的是指针,而不是对象

为了更好地澄清这个概念,请考虑以下内容:

NSMutableString * a = [NSMutableString stringWithString:@"hello"];
NSMutableString * b = a;
[a setString:@"hola"];
NSLog(@"%@", a); // "hola"
NSLog(@"%@", b); // "hola"

如果你在赋值对象,b 会是 a 的一个副本,对 a 的进一步修改不会影响到 b

而实际上你得到的是 ab 是指向堆上同一个对象的两个指针。


我喜欢你的底线。把它加粗...这样我就可以给你+1 :) - Anoop Vaidya
1
它确实值得大胆尝试。 - Gabriele Petronella
5
类似于 @"Hello" 这样的字符串字面量会被编译进二进制文件中,它们不会被翻译成 alloc:initWithUTF8String - Martin R
1
@DanZimm 是的,我的意思是要遵循常规的对象生命周期。显然最终这只是C语言,因此您可以轻松地在堆栈上拥有任何结构体。但是我很怀疑任何API都能在该对象上正常工作 ;) - Gabriele Petronella
1
为堆栈对象专门创建一个API;D - DanZimm
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接