iOS 開發刷題系列三:NSString 引用計數
下面的程式會輸出什麼?
NSMutableArray *ary = [[NSMutableArray array] retain];
NSString *str = [NSString stringWithFormat:@"123456789"];
NSString *longStr = [NSString stringWithFormat:@"1234567890"];
[str retain];
[longStr retain];
[ary addObject:str];
[ary addObject:longStr];
NSLog(@"str = %ld", (unsigned long)[str retainCount]);
NSLog(@"longStr = %ld", (unsigned long)[longStr retainCount]);
[str retain];
[str release];
[str release];
[longStr retain];
[longStr release];
[longStr release];
NSLog(@"str = %ld", (unsigned long)[str retainCount]);
NSLog(@"longStr = %ld", (unsigned long)[longStr retainCount]);
[ary removeAllObjects];
NSLog(@"str = %ld", (unsigned long)[str retainCount]);
NSLog(@"longStr = %ld", (unsigned long)[longStr retainCount]);
輸出結果
2018-07-03 13:54:59.951143+0800 BlockTestDemo[13502:2107264] str = -1
2018-07-03 13:54:59.951374+0800 BlockTestDemo[13502:2107264] longStr = 3
2018-07-03 13:54:59.951613+0800 BlockTestDemo[13502:2107264] str = -1
2018-07-03 13:54:59.951717+0800 BlockTestDemo[13502:2107264] longStr = 2
2018-07-03 13:54:59.951956+0800 BlockTestDemo[13502:2107264] str = -1
2018-07-03 13:54:59.952044+0800 BlockTestDemo[13502:2107264] longStr = 1
在網上搜尋了一下,一般人給出的答案是:當字串長度小於10時,字串是儲存在常量區,沒有引用計數。如果長度大於等於10呢,就會被複制到堆去,有引用計數。
後來又出現了一個詞:Tagged Pointer 具體瞭解一下。 嘗試著輸出字串的class,發現兩者的類名是不同的:
NSString *str = [NSString stringWithFormat:@"123456789"];
NSString *longStr = [NSString stringWithFormat:@"1234567890"];
NSLog(@"str %s %p", object_getClassName(str), str);
NSLog(@"longStr %s %p", object_getClassName(longStr), longStr);
2018-07-03 13:54:59.950804+0800 BlockTestDemo[13502:2107264] str NSTaggedPointerString 0xa1ea1f72bb30ab19
2018-07-03 13:54:59.950979+0800 BlockTestDemo[13502:2107264] longStr __NSCFString 0x60c000224f20
Tagged Pointer專門用來儲存小的物件,例如NSNumber和NSDate
Tagged Pointer指標的值不再是地址了,而是真正的值。所以,實際上它不再是一個物件了,它只是一個披著物件皮的普通變數而已。所以,它的記憶體並不儲存在堆中,也不需要malloc和free。
這應該也是上面的NSString在長度小於10的時候,沒有引用計數的原因了。
引申
這種情況引申出另外一道題:
@property (nonatomic, strong) NSString *strongStr;
dispatch_queue_t queue = dispatch_queue_create("strongStr", DISPATCH_QUEUE_CONCURRENT);
for (int i = 0; i < 100000; i++) {
dispatch_async(queue, ^{
self.strongStr = [NSString stringWithFormat:@"ab %d", i];
});
}
如果將dispatch_async 裡面的內容改成:
self.strongStr = [NSString stringWithFormat:@"abcdefghijklmn %d", i];
會如何?
前者不會crash, 而後者會crash。
我們來看一下strongStr的setter方法:
- (void)setStrongStr:(NSString *)strongStr {
if (strongStr == _strongStr) return;
id pre = _strongStr;
[strongStr retain];//1.先保留新值
_strongStr = strongStr;//2.再進行賦值
[pre release];//3.釋放舊值
}
結合上面的Tagged Pointer的解釋,呼叫retain or release時strongStr的引用計數一直都是-1;
而對於後者,strongStr實際上是一個物件,retain會使引用計數+1,release會使引用計數 -1;
而對於多執行緒非同步並行執行setStrongStr方法,可能會出現這種情況:多個執行緒拿到同一個舊值,然後給strongStr賦值不同的新值,然後在對舊值的release時候,出現多次release,程式crash;
相關文章
- iOS開發– ARC與引用計數iOS
- IOS開發系列——UIWebView專題iOSUIWebView
- 刷題系列 - 計算爬樓梯不同步數的方法數
- iOS開發之基礎篇(2)—— NSString、NSMutableStringiOS
- iOS引用計數管理之揭祕計數儲存iOS
- iOS-NSStringiOS
- iOS開發系列--IOS程式開發概覽iOS
- iOS擷取NSString字串iOS字串
- 玩轉iOS開發:iOS中的Socket程式設計(三)iOS程式設計
- 【IOS開發基礎系列】Cocoa基礎專題iOS
- 玩轉iOS開發:iOS中的GCD開發(三)iOSGC
- 怎麼解決引用計數 GC 的迴圈引用問題?GC
- iOS NSString真是個奇葩啊!iOS
- iOS NSString字串擷取方法iOS字串
- iOS開發 - 動畫實踐系列iOS動畫
- iOS開發系列--UITableView全面解析iOSUIView
- iOS NSString中實用的方法iOS
- iOS NSString 字串的特殊處理iOS字串
- ios NSString與LongValue,usignedLongValue,longlongValueiOS
- IOS FoundationKit (NSString) 知識彙總iOS
- 【c++】引用計數C++
- iOS開發系列--檢視切換iOS
- 100個iOS開發/設計面試題大全iOS面試題
- 刷題系列 - K-th 語法
- Leetcode刷題系列彙總LeetCode
- Leetcode刷題628. 三個數的最大乘積LeetCode
- iOS開發之多執行緒程式設計總結(三)iOS執行緒程式設計
- iOS圖文混排與NSString轉換iOS
- iOS 開發(三) MVVM 架構篇iOSMVVM架構
- iOS開發捷徑學習(三)iOS
- iOS開發系列--C語言之指標iOSC語言指標
- ArcGIS for iOS 開發系列(1) – 基本概念iOS
- iOS引用轉換:Foundation與Core Foundation物件互相轉換(__CFString轉NSString,void *轉id等等)iOS物件
- swift自動引用計數Swift
- 引用計數 vs. GCGC
- AAAS:研究發現論文標題越短引用次數越多
- iOS開發系列--打造自己的“美圖秀秀”iOS
- iOS開發系列--C語言之預處理iOSC語言