为什么不需要解除引用NSString指针?

Dee*_*pak 7 c objective-c nsstring

在示例中

NSString *message = @"Hello";
message = @"World";
Run Code Online (Sandbox Code Playgroud)

如果消息只是一个指针,为什么我不需要明确说出消息中的任何内容现在等于*message = @"World";C中的字符串或类似?

Gab*_*lla 14

免责声明

下面的讨论给出了一个总体思路,说明为什么你永远不会在Objective-C中取消引用指向对象的指针.但是,关于NSString文字的具体情况,这不是现实中发生的事情.虽然下面描述的结构仍然是正确的,并且可能以这种方式工作,但实际发生的是字符串文字的空间在编译时分配,并且您得到它的地址.字符串文字也是如此,因为它们是不可变的和常量的.为了提高效率,每个文字只分配一次.

事实上

NSString * a = @"Hello";
NSString * b = @"Hello";
NSLog(@"%@ %p", a, a); // Hello 0x1f4958
NSLog(@"%@ %p", b, b); // Hello 0x1f4958
Run Code Online (Sandbox Code Playgroud)

原始答案

因为它会被翻译成

message = [[NSString alloc] initWithUTF8String:"Hello"]];
Run Code Online (Sandbox Code Playgroud)

这将归结为

message = objc_msgSend(objc_msgSend(objc_getClass("NSString"), @selector(alloc)), @selector(initWithUTF8String:), "Hello");
Run Code Online (Sandbox Code Playgroud)

现在,如果我们看看签名 objc_msgSend

id objc_msgSend(id theReceiver, SEL theSelector, ...)
Run Code Online (Sandbox Code Playgroud)

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

typedef struct objc_object {
    Class isa;
} *id;
Run Code Online (Sandbox Code Playgroud)

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

所以最后@"string"会转换一个函数调用,它会产生一个指向对象的指针(objc_object如果你愿意的话,就是一个结构),这正是你需要分配给它的东西message.

底线,您指定指针,而不是对象.

为了更好地阐明最后的概念,请考虑这一点

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

如果您正在分配对象,那b将是一个副本,a并且任何进一步的修改a都不会受到影响b.

相反,你得到的是a并且b是指向堆中同一对象的两个指针.

  • 像`@"Hello"`这样的字符串文字被编译成二进制文件,它们不会被翻译成`alloc:initWithUTF8String`. (5认同)