iOS 讀書筆記
Pro Multithreading And Memory Management for iOS and OS X
這本書是看網路Blog時有人介紹的,主要內容就三章ARC
BLOCK
GCD
作者是兩個日本人寫的,衝著自己對Block需要再加強,所以興衝衝去買了簡體中文版,我是覺得需要看熟的東西還是不要考驗自己英文比較好 w 而且外國人也說翻的很爛ww。

這部很好看,超展開 OP2 也很熱血好聽~打翻你對英雄的印象。
一開始先來介紹一下
- #ARC
一開始是講引用計數和內存管理,因為自己這方面也算熟,所以跳過不看了。
直接跳到重點 “ARC”
ARC下有四種所有權修飾符
- __strong
- __weak
- __unsafe_unretained
- __autoreleasing
__string
所有的id類型和對象類型默認都是__strong 的
也就是說id obj = [[NSobject alloc]init]
等價於
id __strong obj = [[NSobject alloc]init]
即使有__strong 修飾符下,超出了變數的作用域(scope),引用還是會消失的
也就是
同理 適用在 [NSMutableArray array] 這種帶有autorelease的返回值。
當然,附有__strong 的變數之間可以互相賦值。
|
|
讓我們看一下內存分析
|
|
需特別說明一下__strong
和__weak
, __autoreleasing
都保証有這些修飾符時,(自動變數)區域變數的初始化為nil。
也就是
|
|
__weak
為什麼要有weak出現呢,因為用了strong後,會產生循環引用的問題。也就是兩個物件互相有了對方的強引用。
下面情況也會產生循環引用
__weak
和__strong
不同,提供了弱引用,也就是不持有對象實例,需注意的是__weak不能顯示的修飾一個Object 如:
|
|
同樣的當它引用的對象被廢棄時,持有對象的弱引用也失效,並賦值nil
給 obj1
也就是__weak的特色,當它引用的對象不存在時,ARC會自動幫你賦值nil,以避免野指標。
__unsafe_unretained
用法其實跟assign 差不多,不過當它引用的對象不存在時,ARC並不會幫你自動賦值nil,所以必須手動設置,跟assign一樣用法即可。
__autoreleasing
在ARC中,通過將對象附加了__autoreleasing修飾符的變數等價於在ARC無效時,調用對象的autorelease方法,即被註冊到autoreleasePool中。
也可以理解為,在ARC有效時,用@autoreleasepool塊替代NSAutorelease類,用附有__autoreleasing 修飾符的變數替代autorelease方法。
不過直接使用__autoreleasing
的情況跟__strong
一樣很少,為什麼呢?
因為我們都知道調用class method的對象返回值都是帶有autorelease的,同理,在一個Method中做為返回值時,也是會幫你註冊到autoreleasepool中的。如:
|
|
另一種情況是使用__weak
也會自動幫你註冊到自動釋放池,為什麼呢?
因為__weak
只持有對象的弱引用,而在訪問對象的過程中,該對象有可能被廢棄,如果把訪問對象加到autoreleasepool中,䢷麼在@autorelease 結束前都能確表該對象存在。
所以使用附有__weak修飾符的變數就必定要註冊到aotoreleasepool中的對象。
最後一個非顯示使用__autoreleasing
的情況就是,我們都是id 預設是__strong
,但是如果是id類型的指標呢 (id *obj)
會變成這樣 id __autoreleasing *obj
同樣的,對象指標 NSObject ** obj
則變成了NSObject *__autoreleasing *obj
。
看到了兩個符號有想到Objc中那邊用的最多呢?沒錯~就是`NSError *error`
所以NSError **error
等價於 NSError *__autoreleasing *error
因為聲明為NSError __autoreleasing 類型的error 作為 *error被賦值,所以能夠返回註冊到autoreleasepool中的對象。
但下面會產生編譯錯誤
此道理同__weak
和__unsafe_unretained
如果當返回時是一個__strong指標類型的話呢?
當然也可以顯示的指定指標類型的所有權修飾符(NSError *__strong *error)
###ARC 有幾個規則,讓我們一一對照一下
- 不能使用retain/release/retainCount/autorelease
- 不能使用 NSAllocateObject/NSDeallocateObject
- 須尊守記憶體管理的方法命名規則
- 不要顯示的調用dealloc
- 使用@autoreleasepool塊替代NSAutoreleasePool
- 不能使用NSZone
- 對象型變數不能做為C語言struct中的成員
- 顯示的轉換”id” 和 “void *”
前六項其實都沒什麼好講,有一點概念的應該都知道這些,第七項struct 問題
當你在struch中寫入objc的對象時,會出現錯誤
可以加__unsafe_unretained修飾符或強制轉換void *(下面講)
如
第八點轉換id 和void* 其實就是__bridge
__bridge_retained
__bridge_transfer
不過這些轉換通常都用於Foundation和Core Foundation中的對象,所以不是今天想講的內容。有興趣可以自行查詢。
在ARC下,類型的屬性也會發生變化。(Property)
屬性的聲明 | 所有權修飾符 |
---|---|
assign | __unsafe_unretained 修飾符 |
copy | __strong 修飾符(但是是賦值到被複製的對象) |
retain | __strong 修飾符 |
strong | __strong 修飾符 |
unsafe_unretained |
unsafe_unretained 修飾符 |
weak | __weak 修飾符 |
所以我朋友說他使用block用strong也可以,因為我記得block是要用copy的,在ARC下會自動幫你管理的。
那我們再來討論一下賦值給__strong
__weak
__autoreleasing
的情況下,程式到底是怎麼運行的呢?
__strong
|
|
雖然調用了兩msgSend()方法,變數作用域結束時,通過objc_release釋䢍為象。雖然ARC下不能使用release,但顯然的編譯器自動幫我們插入了release。
那看看由class method時會是什麼情況
中間程式碼中多了一行obj_retainAutoreleasedReturnValue,那麼什麼是obj_retainAutoreleasedReturnValue呢,它主要用于最優化程式運行。
顧名思義,它用于自己持有(retain)對象,但它持有的對象應為返回註冊到autoreleasepool中的對象,也等同於函數的返回值。
obj_retainAutoreleasedReturnValue是成對的,相對的是obj_autoreleasedReturnValue,它用於當alloc這些以外的class方法返回對象的時候。
那麼obj_autoreleasedReturnValue
有什麼作用呢?obj_autoreleasedReturnValue
會檢查使用該函數的方法或調用方的執行命令表,如果方法或函數的調用方裡有obj_retainAutoreleasedReturnValue
時,他就不會再次註冊到autoreleasepool中而是直接返回方法或函數。
__weak
- 若附有
__weak
修飾符的變數所引用的對象不存在時,則nil賦值給該變數。 - 使用附有
__weak
修飾符的變數,即是使用註冊到autoreleasepool中的對象。
唯一需要注意的是,如果大量使用附有__weak
修飾符的變數時,則會消耗相應的CPU資,比較好的方法是只在需要避免循環引用時使用__weak
修飾符。
因為使用__weak
會被自動註冊到autoreleasepool中,所以重複的使用同一個變數時,也會重複的註冊到autoreleasepool中
|
|
在 “tmp = obj” 時,對象註冊到autoreleasepool中只有1次。
__autoreleasing
其實內部實現跟weak不太一樣,不過大致上跟__weak
差不多,現在iOS開發上也不需要支持iOS 4的機器,所以幾乎可以不用太管這個修飾符。