NSString 特性分析學習

我們都知道NSString是一個Objective-C的類,但是我們有時發現它的對象在內存管理上貌似和其他的對象有一些區別。比如有時你會發現對一個NSString進行copy操作時,它還是原本的對象,實際上并未拷貝對象。本篇就來研究下這個問題 。
原文鏈接

1. NSString內存管理特性分析

1.1 準備

為了方便測試,我先寫了個宏,用來打印NSStringisa、內存地址、值、retainCount。 注:為了了解內存特性,后面的代碼都使用了手動內存管理。

 #define TLog(_var) ({ NSString *name = @#_var; NSLog(@"%@: %@ -> %p : %@  %d", name, [_var class], _var, _var, (int)[_var retainCount]); })
1.2 NSString的創建
1.2.1 測試NSString

在objc中,我們一般通過幾種方法來創建NSString呢,一般有三種方法,現在我們就分別對這三種情況寫段測試代碼,如下:

NSString *str1 = @"1234567890";    TLog(str1);
//str1: __NSCFConstantString -> 0x715ec : 1234567890  -1

NSString *str2 = [NSString stringWithString:@"1234567890"];        TLog(str2);
//str2: __NSCFConstantString -> 0x715ec : 1234567890  -1

NSString *str3 = [NSString stringWithFormat:@"1234567890"];        TLog(str3);
//str3: __NSCFString -> 0x1557cb50 : 1234567890  1

看到上面這段測試代碼,我們可以發現幾點同我們想象不同的地方:

第一種方式和第二種方式創建出來的NSString時一模一樣的,isa__NSCFConstantString,內存地址一樣,retainCount-1.

第三種方式創建的NSString和創建其他objc對象類似的,在堆上分配內存,初始retainCount為1.

這里面有幾個疑問:

什么是__NSCFConstantString

為什么第一種和第二種NSString的內存地址是一樣的?

為什么他們的retainCount-1

1.2.2NSString創建的寫法

其實上面第一種寫法和第二種寫法是完全一樣的,沒有任何區別,從iosSDK6開始,第二種寫法已經被遺棄了,如果用第二種寫法創建 NSString, 編譯器就會報一個警告。

1.2.3 retainCount-1是什么情況

首先retainCountNSUInteger的類型,其實上面的打印是將它作為int類型打印。所以它其實不是-1,它的實際值是4294967295

在objc的 retainCount 中,如果對象的retainCount為這個值,就意味著“無限的retainCount”,這個對象是不能被釋放的。
所有的 __NSCFConstantString對象的retainCount都為-1,這就意味著 __NSCFConstantString不會被釋放,使用第一種方法創建的NSString,如果值一樣,無論寫多少遍,都是同一個對象。而且這種對象可以直接用 == 來比較
NSString *str1 = @"1234567890";    TLog(str1);
//str1: __NSCFConstantString -> 0x715ec : 1234567890  -1

NSString *str2 = @"1234567890";    TLog(str2);
//str2: __NSCFConstantString -> 0x715ec : 1234567890  -1

assert(@"abc"==@"abc"); //一直正確

1.3 NSStringretaincopymutableCopy

我們寫一段代碼分別對 __NSCFConstantString__NSCFString進行retaincopy測試

__NSCFConstantString

NSString *str1 = @"a";    TLog(str1);
NSString *str2 = [str1 retain];  TLog(str2);
NSString *str3 = [str1 copy]; TLog(str3);
NSString *str4 = [str1 mutableCopy]; TLog(str4);

/*
 str1: __NSCFConstantString -> 0x7c5e0 : a  -1
 str2: __NSCFConstantString -> 0x7c5e0 : a  -1
 str3: __NSCFConstantString -> 0x7c5e0 : a  -1
 str4: __NSCFString -> 0x1559eb80 : a  1
*/

上面的測試可以看出,對一個__NSCFConstantString進行retaincopy操作都還是自己,沒有任何變化,對其mutableCopy操作可將其拷貝到堆上,retainCount1.

__NSCFString

NSString *str1 = [@"a" mutableCopy];    TLog(str1);
NSString *str2 = [str1 retain];  TLog(str2);
NSString *str3 = [str1 copy]; TLog(str3);
NSString *str4 = [str1 mutableCopy]; TLog(str4);

/*
 str1: __NSCFString -> 0x17d6d280 : a  1
 str2: __NSCFString -> 0x17d6d280 : a  2
 str3: __NSCFConstantString -> 0x3bd40090 : a  -1
 str4: __NSCFString -> 0x17e684d0 : a  1
*/

上面的測試中,我們發現,對__NSCFString進行retainmutableCopy操作時,其特性符合正常的對象特性。但是對其copy時,它卻變成了一個__NSCFConstantString對象!

為了確定什么情況下才會出現這種現象我們多做一些測試

NSString *str1 = [[@"a" mutableCopy] copy];    TLog(str1);
NSString *str2 = [NSString stringWithFormat:@"%s","a"];  TLog(str2);
NSString *str3 = [[[@"path/a" lastPathComponent] mutableCopy] copy]; TLog(str3);

NSString *str4 = [[@"b" mutableCopy] copy]; TLog(str4);
NSString *str5 = [[@"c" mutableCopy] copy]; TLog(str5);
NSString *str6 = [[@"d" mutableCopy] copy]; TLog(str6);
NSString *str7 = [[@"e" mutableCopy] copy]; TLog(str7);
NSString *str8 = [[@"f" mutableCopy] copy]; TLog(str8);

NSString *str9 = [[@"\\" mutableCopy] copy]; TLog(str9);
NSString *str10 = [[@"$" mutableCopy] copy]; TLog(str10);
NSString *str11 = [[@"." mutableCopy] copy]; TLog(str11);
NSString *str12 = [[@"aa" mutableCopy] copy]; TLog(str12);
/*
str1: __NSCFConstantString -> 0x3bd40090 : a  -1
str2: __NSCFConstantString -> 0x3bd40090 : a  -1
str3: __NSCFConstantString -> 0x3bd40090 : a  -1
str4: __NSCFString -> 0x175ab390 : b  1
str5: __NSCFString -> 0x176a5ce0 : c  1
str6: __NSCFString -> 0x175ab960 : d  1
str7: __NSCFString -> 0x176a5cc0 : e  1
str8: __NSCFString -> 0x176a5d50 : f  1
str9: __NSCFString -> 0x176a5d60 : \  1
str10: __NSCFString -> 0x176a6700 : $  1
str11: __NSCFString -> 0x175ab750 : .  1
str12: __NSCFString -> 0x175ab760 : aa  1
*/

起初我以為是ASCII字符比較特殊,經過上面這一段的測試發現,只有@“a”才有這樣的現象,我又用模擬器測試了這一段代碼,結果得到的都是__NSCFString的對象。這個問題研究了一會,沒找到答案,暫時就放下了,好在這個對于我們編碼沒什么影響。

2. 小結

經過這一系列的測試分析,讓我們認識了__NSCFConstantString以及它的一些特性,它是在編譯時就決定的,不能在運行時創建。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 轉自:https://blog.cnbluebox.com/blog/2014/04/16/nsstringte-...
    生產八哥閱讀 446評論 0 0
  • 對于NSString 何時使用strong,何時使用copy,首頁讓我們來具體的了解一下NSString的一些內部...
    當前明月閱讀 567評論 0 5
  • 內存管理 簡述OC中內存管理機制。與retain配對使用的方法是dealloc還是release,為什么?需要與a...
    丶逐漸閱讀 2,008評論 1 16
  • 1.項目經驗 2.基礎問題 3.指南認識 4.解決思路 ios開發三大塊: 1.Oc基礎 2.CocoaTouch...
    陽光的大男孩兒閱讀 5,031評論 0 13
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,211評論 30 472