nsstring是存储在堆上还是堆栈上初始化的好方法是什么



我有两个新问题:

1)考虑这一行:

NSString *myString = [[NSString alloc] initWithString: @"Value"]; 

我学到了两件事,但我想确认一下:据我所知,"alloc"消息表明NSString的实例将存储在"堆"内存中。我还了解到,诸如"字符"之类的原始变量存储在"堆栈"内存中。

这是否意味着:

  • NSString的实例存储在堆内存中;
  • 并且这个对象有一个iVar指针(当initWithString方法被调用时)到原始"字符"的"值"字符串,它驻留在堆栈内存中?这在现实中是如何运作的呢?

第二个问题直接相关,并使我个人陷入困境(可能是因为我遗漏了一点):2)你会参考哪一种方法,为什么?:

NSString *myString = [[NSString alloc] initWithString: @"Value"]; 
NSString *myString = @"Value"; 

如果我的第一个问题得到确认,这两种方法都应该"最终"指向存储在堆栈内存中的字符。因此,我实际上不明白使用第一个选项的目的,并为保留计数而烦恼。

简短的回答:在这种情况下,两行都有相同的结果,可以将字符串常量直接分配给myString

长答:

Objective-C对象确实是在堆上分配的。然而,"原始"值并不总是存储在堆栈中。局部变量存储在堆栈中,无论它们是否是原始变量。(例如,您可以声明一个局部变量,它是一个结构体,它不被认为是原始的。)您可以在堆上存储原始值,但在这种情况下访问它们的唯一方法是通过指针。例如:

int *someInt = malloc(sizeof(int));  // allocate a block of memory to hold an int
*someInt = 42;                       // store data in that memory
总是使用指针来引用Objective-C对象的原因是对象总是在堆上分配的。如果你想在堆栈上存储一些东西,编译器需要知道它的大小。在Objective-C中,对象的大小直到程序实际运行时才知道。

回到字符串。尝试执行以下两行:

NSString *foo = [[NSString alloc] initWithString:@"foo"];
NSString *bar = @"foo";

如果你在第二行之后换行,你会发现foobar包含相同的地址;也就是说,它们指向同一个对象。因为NSString对象是不可变的,创建一个带有常量字符串的对象只会返回一个指向该常量的指针。

为什么在NSString中有-initWithString:如果那是它的全部功能?NSString是一个"类簇"也就是说NSString是几个不同内部类的公共接口。如果你传递一个NSString*它不是一个常量到-initWithString:,你得到的对象可能是一个不同类的实例而不是你使用常量时得到的。作为一个类集群,NSString向你隐藏了很多实现细节,这样你就可以获得不同类型字符串的良好性能,而不必担心它是如何工作的。

NSString s很有趣,因为直到最近它们还是唯一一种可以作为文字提供的Objective-C对象类型。据我所知,iOS 4和OS X 10.6中新增的block对象也是最近新增的,但它们有自己的特殊规则,所以我只是为了完整起见才提出来。

C原语可以存储在堆或堆栈中。例如:

- (void)someMethod
{
    int i = 3; // i is on the stack
}
- (void)someOtherMethod
{
    int *i = (int *)malloc(sizeof(int)); // i now points to an 'int' on the heap
}

大多数Objective-C对象只能存储在堆上。你说alloc在堆上提供一个对象的新副本是非常正确的,而你调用myString的结果将是在堆上有一个指向NSString的指针。

然而,@""语法是创建对象的简写。@"Value"实际上创建了一个对象字面量。例如,你可以这样写:

NSLog(@"%@", [@"Value" substringFromIndex:1]);

输出将是' value '。您可以将substringFromIndex:消息发送给@"Value",因为它是一个文字对象。

确切地说,NSStringinitWithString:所做的是一个具体的实现,但你可以肯定的是,如果需要的话,它将获取指向的东西的副本。否则你会看到奇怪的行为,如果你这样做:

NSMutableString *mutableString = [NSMutableString stringWithString:@"String"];
NSString *immutableString = [NSString stringWithString:mutableString];
[mutableString appendString:@" + hat"];
// immutableString would now have mutated if it was simply
// keeping a reference to the string passed in
因此,您不必担心传递给它的任何东西的生命周期。这是NSString的工作。

在实践中,NSString对象字面量实际上永远不会过期,所以这一点有点没有意义。然而,如果你使用initWithUTF8String:或其他接受C文字的东西,并且该C文字在堆栈上,你仍然没有什么可担心的,因为NSString会处理它。

回答你的第二个问题,我倾向于第二个版本,因为它更短,因此更清楚地表明你打算做什么。从理论上讲,后者对性能有一些好处——特别是如果您在多个地方使用相同的文字——但它们是如此令人难以置信地微不足道,以至于现在不值得考虑。

相关内容

最新更新