《Objective-C高階程式設計:引用計數和strong ,weak
阿新 • • 發佈:2019-02-19
轉載請註明出處
如果覺得文章對你有所幫助,請通過留言或關注微信公眾帳號wangzzstrive來支援我,謝謝!
二、引用計數原理
iOS中說到記憶體管理,不管是手動還是ARC,都離不開引用計數,我一直很好奇引用計數到底是怎麼儲存的呢?可能的實現方式有兩種:
蘋果在實現時,凡是使用引用計數的方法,包括retainCount、retain、release方法都呼叫了同一個方法,該方法的實現原理簡化後如下所示:
蘋果這種實現方式的優點是: 不用再每個物件記憶體塊中考慮引用計數所站的記憶體; 引用計數表中儲存的有各個物件的記憶體地址,可以直接通過各條引用技術追蹤到對應的物件記憶體塊,在除錯的時候很有用。
一、前言
這本書由日本人Kazuki Sakamoto和Tomohiko Furumoto所著,主要講了ARC、Blocks、GCD三個模組。總體來說,書的內容講的挺深的,小日本寫的東西還真是不錯。作者一直試圖從原理上闡述ARC、block、GCD的實現機制,不像大部分國內相關書籍中只介紹其然,這是一本探索所以然的書。鑑於上述三個模組是每個試圖在iOS開發上有所造詣的同學必須掌握的東西,強烈建議已經有一定Objective-C功底的同學看看。 從事iOS開發以來一直都是使用手動記憶體管理,因此對引用計數的理解還是比較透徹的。直到開發拉手團購6.0版的時候,開始使用ARC,上手後的感覺是以後的記憶體管理都是ARC的天下。在這本書中,作者也著重介紹了手動記憶體管理及其實現。書中講的內容大部分之前都看過,不過自己看的不夠系統。斷斷續續花了二十天左右時間讀完這本書,還是收穫不小,下面將自認為值得記住的地方列舉出來:
二、引用計數原理
iOS中說到記憶體管理,不管是手動還是ARC,都離不開引用計數,我一直很好奇引用計數到底是怎麼儲存的呢?可能的實現方式有兩種:
- 鑑於Objective-C物件都有引用計數,所以每個物件都應該儲存自己的引用計數
- runtime統一儲存所有物件的引用計數
蘋果在實現時,凡是使用引用計數的方法,包括retainCount、retain、release方法都呼叫了同一個方法,該方法的實現原理簡化後如下所示:
-
int _CFDoExternRefOperation(
- {
- CFBasicHashRef table = 取得物件的散列表(obj);
- int count;
- switch(op) {
- case OPERATION_retainCount;
- count = CFBasicHashGetCountOfKey(table, obj);
- return count;
- case OPERATION_retain:
- CFBasicHashAddValue(table, obj);
- return obj;
-
case OPERATION_release
- count = CFBasicHashRemoveValue(table, obj);
- return0 == count;
- }
- }
蘋果這種實現方式的優點是: 不用再每個物件記憶體塊中考慮引用計數所站的記憶體; 引用計數表中儲存的有各個物件的記憶體地址,可以直接通過各條引用技術追蹤到對應的物件記憶體塊,在除錯的時候很有用。
三、__autoreleasing關鍵字
看我完這本書後,對該修飾符有了更深的理解,有以下幾個方面: 1、ARC下使用__autoreleasing修飾符修飾的變數會被註冊到autoreleasepool中,和非ARC下呼叫autorelease方法的效果相同; 2、當方法名不是alloc/new/copy/mutableCopy時,使用return返回的物件強引用會被自動註冊到autoreleasepool。比如:- + (id)array
- {
- id obj = [[NSArray alloc] init];
- return obj;
- }
- id __weak obj1 = obj0;
- NSLog("class=%@", [obj1 class]);
- //等價於以下程式碼
- id __weak obj1 = obj0;
- id __autoreleasing tmp = obj1;
- NSLog("class=%@", [tmp class]);
四、__weak關鍵字
這部分需要著重介紹的是__weak關鍵字。 我們知道,當一個__weak型別的指標指向的物件被釋放時,該指標會自動被置成nil,因此__weak關鍵字修飾的指標又被稱為智慧指標。那麼這個功能是如何實現的呢? 1、編譯器做的事 先看下面這段程式碼:- {
- id __weak obj1 = obj;
- }
- id obj1;
- objc_initWeak(&obj1, obj);
- objc_destoryWeak(&obj1);
- objc1 = 0;
- objc_storeWeak(&obj1, obj);
- objc_storeWeak(&obj1, 0);
- id obj1;
- obj1 = 0;
- objc_storeWeak(&obj1, obj);
- objc_storeWeak(&obj1, 0);
- 以當前物件的地址作為key,從weak表中獲取對應的值----指向該物件的__weak型別的指標變數;
- 將取到的所有指標變數的值賦值為nil;
- 從weak表中刪除該key對應的整條記錄。