2011-09-11 131 views
8

一個很好的方式,我有2個新的問題:被存儲在堆或堆棧上NSString的,什麼是初始化一個

1)考慮這一行:

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

有兩件事情我瞭解,但我想確認: 據我所知,「alloc」消息表明NSString的實例將存儲在「堆」內存中。 我也理解像「chars」這樣的原始變量存儲在「堆棧」內存中。

這是否意味着:

  • 的NSString的實例存儲在堆存儲器;
  • 而且這個對象有一個iVar指針(當initWithString方法被調用時)到原始「chars」的「Value」字符串,該字符串駐留在堆棧內存中? 這是如何工作的現實?

第二個問題是直接相關的,並導致了我個人的困境(也許是因爲我缺少一個點): 2)你去看這兩種方法的,爲什麼?:

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

如果我的第一個問題得到證實,兩種方法都應該「最終」指向存儲在堆棧內存中的字符。因此,我實際上並沒有看到使用第一個選項的目的,並且受到保留計數的困擾。

回答

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 

我們總是使用指針指Objective-C對象的原因是對象總是在堆上分配。如果你想在棧上存儲一些東西,編譯器需要知道它的大小。在Objective-C中,直到程序實際運行時才知道對象的大小。

所以,回到你的字符串。嘗試執行以下兩行:

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

如果第二線突破之後,你會發現foobar包含相同的地址;也就是說,他們指向同一個對象。因爲NSString對象是不可變的,所以用常量字符串創建一個就返回一個指向該常量的指針。

爲什麼在NSString中甚至有一個-initWithString:如果只是這樣呢? NSString是一個「類集羣」,也就是說NSString是幾個不同內部類的公共接口。如果你將一個不是常量的NSString *傳遞給-initWithString:,那麼你返回的對象可能是一個不同於你在使用常量時得到的類的實例。作爲類集羣,NSString隱藏了大量的實現細節,這樣您就可以獲得不同類型字符串的良好性能,而不必擔心它是如何工作的。

4

NSString s很有趣,因爲它們直到最近纔是唯一可以作爲文字提供的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 
} 

大多數Objective-C對象只能存儲在堆上。您完全可以說alloc在堆上提供了一個新對象,並且您的myString調用的結果將是一個指向堆中NSString的指針。

但是,@""語法是創建對象的簡寫。 @"Value"實際上創建了一個對象文字。所以,舉例來說,你可以這樣做:

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

並且輸出將是'alue'。您可以將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會處理它。

在回答你的第二個問題時,我傾向於第二個版本,理由是它更短,因此更清楚地表明你打算做什麼。後者有一些理論上的性能好處 - 特別是如果你在多個地方使用相同的文字 - 但它們如此令人難以置信的微不足道,因爲現在不值得考慮。