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裡面,系統會判斷物件是不是指向常量。