Tra*_*ace 8 memory theory objective-c nsstring
我有两个新问题:
1)考虑这一行:
NSString *myString = [[NSString alloc] initWithString: @"Value"];
Run Code Online (Sandbox Code Playgroud)
我学到了两件事,但我想确认一下:据我所知,"alloc"消息表明NSString的实例将存储在"堆"内存中.我也理解原始变量如"字符"存储在"堆栈"存储器中.
这是否意味着:
第二个问题是直接相关的,并导致我个人困境(可能是因为我错过了一点):2)你会咨询哪两种方法以及为什么?:
NSString *myString = [[NSString alloc] initWithString: @"Value"];
NSString *myString = @"Value";
Run Code Online (Sandbox Code Playgroud)
如果我的第一个问题得到确认,两种方法都应该"最终"指向存储在堆栈内存中的字符.因此,我实际上并没有看到使用第一个选项的目的并且被保留计数所困扰.
Cal*_*leb 13
简短回答:在这种情况下,两行都有相同的结果将字符串常量直接赋值为myString.
更长的回答:
确实,Objective-C对象是在堆上分配的.但是,"原始"值始终存储在堆栈中并非如此.局部变量存储在堆栈中,无论它们是否是原始的.(例如,您可以声明一个结构的局部变量,它不被认为是原始的.)您可以在堆上存储原始值,但在这种情况下访问它们的唯一方法是通过指针.例如:
int *someInt = malloc(sizeof(int)); // allocate a block of memory to hold an int
*someInt = 42; // store data in that memory
Run Code Online (Sandbox Code Playgroud)
我们总是使用指针来引用Objective-C对象的原因是对象总是在堆上分配.如果要在堆栈上存储某些内容,编译器需要知道它的大小.在Objective-C中,在程序实际运行之前,不知道对象的大小.
所以,回到你的字符串.尝试执行以下两行:
NSString *foo = [[NSString alloc] initWithString:@"foo"];
NSString *bar = @"foo";
Run Code Online (Sandbox Code Playgroud)
如果你在第二行之后中断,你会发现它foo并bar包含相同的地址; 也就是说,它们指向同一个对象.因为NSString对象是不可变的,所以创建一个具有常量字符串的对象只返回指向该常量的指针.
为什么它甚至-initWithString:在NSString中都是如此呢?NSString是一个"类集群",也就是说NSString是几个不同内部类的公共接口.如果传递的NSString*不是常量-initWithString:,则返回的对象可能是与使用常量时不同的类的实例.作为类集群,NSString会隐藏很多实现细节,以便您可以获得不同类型字符串的良好性能,而无需担心它是如何工作的.
NSStrings很有意思,因为直到最近它们才是唯一可以作为文字提供的Objective-C对象类型.在iOS 4和OS X 10.6中添加的块对象是我所知道的另一个最近的添加,但它们有自己的特定规则,所以我提到这只是为了完整性.
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
}
Run Code Online (Sandbox Code Playgroud)
大多数Objective-C对象只能存储在堆上.你说alloc在堆上提供一个对象的新副本是完全正确的,你myString调用的结果将是指向堆上的NSString的指针.
但是,@""语法是创建对象的简写.@"Value"实际上创建了一个对象文字.所以,例如,您可以这样做:
NSLog(@"%@", [@"Value" substringFromIndex:1]);
Run Code Online (Sandbox Code Playgroud)
输出将是'alue'.您可以发送substringFromIndex:消息,@"Value"因为它是一个文字对象.
究竟是什么NSString与做initWithString:是实现特有的,但你可以肯定,这将需要的东西拷贝指出,如果需要.否则你会看到奇怪的行为,如果你做了这样的事情:
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
Run Code Online (Sandbox Code Playgroud)
因此,您无需担心传递给它的任何事物的生命周期.处理这NSString件事是有责任的.
在实践中,NSString对象文字实际上永远不会过期,因此这一点有点没有实际意义.但是,如果你使用了initWithUTF8String:或其他需要C文字的东西,并且C文字在堆栈中,你仍然没有什么可担心的,因为NSString它会处理它.
在回答你的第二个问题时,我赞成第二个版本,理由是它更短,因此更清楚地展示了你打算做什么.后者有一些理论上的性能优势 - 特别是如果你在多个地方使用相同的文字 - 但它们是如此令人难以置信的微不足道,以至于现在不值得考虑.