1. 程式人生 > >iOS NSString的記憶體情況

iOS NSString的記憶體情況

在iOS 的記憶體管理裡面,NSString算是一個比較特殊的情況,它是一個OC物件,可是它的記憶體管理跟它指向的內容有關。

主要分兩種:

(1)NSString 指向一個常量字串,即在編譯時已經確定的值,那麼NSString就不受記憶體管理

(2)除開第一種情況,那麼NSString就跟其他OC物件一樣,受retainCount控制。

 測試程式碼

NSString *str11 = @"dsfsdfdddd";
NSString *str22 = [NSString stringWithFormat:@"dsfdsfds"];
NSString *str33 = [NSString stringWithString:str22];
NSLog(@"str11:%lu --- str22:%lu --- str33:%lu", [str11 retainCount], [str22 retainCount], [str33 retainCount]);

輸出:

str11:18446744073709551615 --- str22:18446744073709551615 --- str33:1

那麼試著輸出在lldb這幾個物件輸出這幾個物件的class

(lldb) po str11.class

__NSCFConstantString

(lldb) po str22.class

NSTaggedPointerString

(lldb) po str33.class

__NSCFString


第一個str11是一個常量字串__NSCFConstantString,他指向一個常量,可以這樣理解,編譯器在編譯的時候,把這個變數值@"dsfsdfdddd"新增到常量表裡面,常量表裡面的變數在APP結束之後才會被釋放,指向這塊常量表的指標都不受retainCount管理(或者這樣理解:所有指向常量的變數在編譯時都被替換成常量地址,那麼就不存在OC指標的記憶體釋放了)

第二個str22比較特殊,如果stringWithFormat裡面直接寫一個字串,那麼編譯器會編譯成一個字串常量,那麼跟第一種情況是一樣的(可能個人理解有偏差)。

如果stringWithFormat需要進行拼接,那麼stringWithFormat會返回一個mutableString型別

測試程式碼:把上面str22的程式碼換成這個

NSString *str22 = [NSString stringWithFormat:@"dsfdsfds%i", 11];

輸出:__NSCFString ,retainCount==1

並且可以在除錯時候看到str22型別是NSMutableString

第三個str33跟str22類似,如果stringWithString引數是個字串物件,如stringWithString:str22,那麼函式返回結果是一個NSMutableString物件;而如果是指定一個字串值,如stringWithString:@"dsadsa",那麼返回的就是一個__NSCFConstantString,這裡應該是編譯器在編譯時自行優化了

NSString *str33 = [NSString stringWithString:@"dsadsa"];

替換成:

NSString *str33 = @"dsadsa";

那就和第一個str11一樣的了

另外retain/copy操作對常量字串無效

比如NSString *str11 = [@"dddd" copy];

str11不會變化,個人理解在 copyWithZone裡面,系統會判斷物件是不是指向常量。