內(nèi)存管理基本原則所有權(quán)關(guān)鍵字ARC使用準(zhǔn)則
通過前面幾篇文章的介紹,,我想大家應(yīng)該對(duì)ARC有了一個(gè)比較完整的理解,。最后,我們來對(duì)ARC做一個(gè)總結(jié),,并把一些未涉及到的細(xì)節(jié)部分再深入討論一下,。 內(nèi)存管理基本原則
所有權(quán)關(guān)鍵字從代碼上看,,有ARC的代碼和沒有ARC的代碼區(qū)別就在下面的幾個(gè)關(guān)鍵字,。 類似 NSObject* 的對(duì)象類型,或者 id 類型1,,當(dāng)ARC有效的時(shí)候,,根據(jù)具體情況,這些關(guān)鍵字必須要使用2,。
接下來,我們結(jié)合下面ARC的使用準(zhǔn)則,,來看看一些使用ARC后的技術(shù)細(xì)節(jié),。 ARC使用準(zhǔn)則為了避免程序秒退的尷尬,ARC有效時(shí),,我們的代碼必須遵循下面的準(zhǔn)則,。
建議使用Objective-C的class來管理數(shù)據(jù)格式,來代替C語言的struct,。不能隱式轉(zhuǎn)換 id 和 void *,。 不能使用 retain/release/retainCount/autorelease內(nèi)存管理完全交給編譯器去做,所以之前內(nèi)存相關(guān)的函數(shù)(retain/release/retainCount/autorelease)不能出現(xiàn)在程序中,。Apple的ARC文檔中也有下面的說明,。
如果我們?cè)诔绦蛑惺褂眠@些函數(shù),,經(jīng)得到類似下面的編譯錯(cuò)誤信息,。 error: ARC forbids explicit message send of ’release’ [o release]; ^ ~~~~~~~ 不能使用 NSAllocateObject/NSDeallocateObject生成并持有一個(gè)Objective-C對(duì)象的時(shí)候,,往往像下面一樣使用NSObject的alloc接口函數(shù),。 id obj = [NSObject alloc]; 實(shí)際上,如果我們看了GNUstep 中關(guān)于 alloc 的代碼就會(huì)明白,,實(shí)際他是使用 NSAllocateObject 來生成并持有對(duì)象實(shí)例的,。換言之,ARC有效的時(shí)候,,NSAllocateObject函數(shù)的調(diào)用也是禁止的,。如果使用,也會(huì)遇到下面的編譯錯(cuò)誤,。 error: ’NSAllocateObject’ is unavailable: not available in automatic reference counting mode 同樣,,對(duì)象釋放時(shí)使用的 NSDeallocateObject 函數(shù)也不能使用,。 不能使用 NSZoneNSZone 是什么?NSZone 是為了防止內(nèi)存碎片而導(dǎo)入的一項(xiàng)措施,。Zone 是內(nèi)存管理的基本單元,,系統(tǒng)中管理復(fù)數(shù)的Zone。系統(tǒng)根據(jù)對(duì)象的使用目的,,尺寸,,分配其所屬的Zone區(qū)域。以提高對(duì)象的訪問效率,,避免不必要的內(nèi)存碎片,。但是,現(xiàn)在的運(yùn)行時(shí)系統(tǒng)(用編譯開關(guān) __OBJC2__ 指定的情況下)是不支持Zone概念的,。所以,,不管ARC是否有效,都不能使用 NSZone,。 不能明示調(diào)用dealloc不管是否使用ARC,,當(dāng)對(duì)象被釋放的時(shí)候,對(duì)象的dealloc函數(shù)被調(diào)用(就像是C++中對(duì)象的析構(gòu)函數(shù)),。在該函數(shù)中,,需要做一些內(nèi)存釋放的動(dòng)作。比如,,當(dāng)對(duì)象中使用了malloc分配的C語言內(nèi)存空間,,那么dealloc中就需要像下面一樣處理內(nèi)存的釋放。
又或者是注冊(cè)的delegate對(duì)象,,觀察者對(duì)象需要被刪除的時(shí)候,,也是在dealloc函數(shù)中動(dòng)作。
如果在ARC無效的時(shí)候,,我們還要像下面一樣,,調(diào)用父類對(duì)象的dealloc函數(shù)。
但是當(dāng)ARC有效的時(shí)候,,[super dealloc];的調(diào)用已經(jīng)被編譯器自動(dòng)執(zhí)行,,已經(jīng)不需要我們明示調(diào)用了。如果你在代碼中還這樣寫,,難免遇到下面的錯(cuò)誤,。 error: ARC forbids explicit message send of ’dealloc’ [super dealloc]; ^ ~~~~~~~ 內(nèi)存管理相關(guān)的函數(shù)必須遵循命名規(guī)則在iPhone開發(fā)之深入淺出 (3) — ARC之前世今生中,我們知道如果是 alloc/new/copy/mutableCopy/init 開頭的函數(shù),,需要將對(duì)象所有權(quán)返回給調(diào)用端,。這條規(guī)則不管ARC是否有效都應(yīng)該被遵守。只是 init 開頭的函數(shù)比較特殊,,他只在ARC下有要求,,而且異??量獭?/p> init 開始的函數(shù)只能返回id型,,或者是該函數(shù)所屬的類/父類的對(duì)象類型,。基本上來說,,init函數(shù)是針對(duì)alloc函數(shù)的返回值,,做一些初始化處理,然后再將該對(duì)象返回,。比如: id obj = [[NSObject alloc] init]; 再比如下面定義的函數(shù)就是不對(duì)的: - (void) initThisObject; 需要是下面這樣: - (id) initWithObject:(id)obj; 另外,,下面名為 initialize 的函數(shù)比較特殊,編譯器將把它過濾掉,,不按上面的規(guī)則處理,。 使用@autoreleasepool代替NSAutoreleasePool在ARC之下,已經(jīng)不能在代碼中使用 NSAutoreleasePool,,我們之前寫 main.m 文件的時(shí)候,,往往像下面這樣寫。
而當(dāng)ARC有效后,,我們需要用@autoreleasepool代替NSAutoreleasePool,。
當(dāng)編譯器看到 @autoreleasepool 定義的塊后會(huì)自動(dòng)生成 NSAutoreleasePool 對(duì)象,并將需要的對(duì)象放入 AutoReleasePool 中,,當(dāng)出方塊的定義范圍時(shí),,pool 中的對(duì)象將被釋放。 Objective-C 對(duì)象不能作為C語言結(jié)構(gòu)體(struct/union)的成員當(dāng)我們?cè)O(shè)置ARC有效,,并在C語言的結(jié)構(gòu)體中定義Objective-C的對(duì)象時(shí),,將出現(xiàn)類似下面的編譯錯(cuò)誤。
error: ARC forbids Objective-C objs in structs or unions NSMutableArray *array; ^ 由于 ARC 是將內(nèi)存管理的細(xì)節(jié)委托給編譯器來做,,所以說編譯器必須要管理對(duì)象的生命周期,。而LLVM 3.0中不存在對(duì)單純C語言構(gòu)造體成員的內(nèi)存管理方法。如果單純是棧對(duì)象,,利用進(jìn)出棧原理,,可以簡(jiǎn)單地維護(hù)對(duì)象的生命周期;而結(jié)構(gòu)體是不行的,,簡(jiǎn)單地理解,,結(jié)構(gòu)體沒有析構(gòu)函數(shù),,編譯器自身不能自動(dòng)釋放其內(nèi)部的 Objective-C 對(duì)象,。 當(dāng)我們必須在C語言的結(jié)構(gòu)體中放入 Objective-C 對(duì)象的時(shí)候,可以使用 void* 轉(zhuǎn)型,,或者使用 __unsafe_unretained 關(guān)鍵字,。比如下面:
這樣一來,,該內(nèi)存信息不在編譯器內(nèi)存管理對(duì)象內(nèi),僅僅是使用而已,,沒有對(duì)象的持有權(quán),。當(dāng)然,對(duì)象所有權(quán)的持有者需要明確的管理他與該結(jié)構(gòu)體的交互,,不要引起不必要的錯(cuò)誤3,。 【id】與【void*】之間需要明示castARC 有效的時(shí)候,由于編譯器幫我們做了內(nèi)存管理的工作,,所以我們不需要太擔(dān)心,。但是當(dāng)與 ARC 管理以外的對(duì)象類型交互的時(shí)候,就需要特殊的轉(zhuǎn)型關(guān)鍵字,,來決定所有權(quán)的歸屬問題,。 主要的轉(zhuǎn)型關(guān)鍵字是: 關(guān)鍵字 解釋
當(dāng)我們?cè)?Core Foundation 對(duì)象類型與 Objective-C 對(duì)象類型之間切換的時(shí)候,需要把握下面的因素:
題外話Xcode 4.3帶來的變化最近隨著 iOS 5.1 的推出,,Xcode也推出了4.3版本。在該版本下,,ARC 有效時(shí)的屬性(@property) 定義的時(shí)候,,如果不明確指定所有權(quán)關(guān)鍵字,那么缺省的就是 strong,。而在 Xcode4.2 中,,即使 strong 也要顯示指定。 在 Xcode4.2 的時(shí)候,,針對(duì)下面的代碼,,
而在 Xcode 4.3 中,我們可以這么做,,
ARC 代碼自動(dòng)變換另外,,Xcode 4.2開始,增加了舊代碼向 ARC 代碼自動(dòng)轉(zhuǎn)換的功能,。有興趣的朋友可以試試,。位置是:
為什么iOS中沒有GC我們已經(jīng)知道ARC并不是GC(垃圾回收)了,那么,,為什么iOS中不支持該機(jī)能呢,?還特意搞出個(gè)ARC來。以下是我的分析:
1. 關(guān)于Objective-C對(duì)象的解釋,,可以參考iPhone開發(fā)入門(7)— 從C/C++語言到Objective-C語言,。 2. 當(dāng)然,如果你不寫,,編譯器會(huì)用缺省的值代替,。具體見iPhone開發(fā)之深入淺出 (3) — ARC之前世今生中的描述。 3. 關(guān)于這一點(diǎn),,可以參考iPhone開發(fā)之深入淺出 (1) — ARC是什么 一文,,明白為什么 __unsafe_unretained 是危險(xiǎn)的。
from http://www./development-of-the-iphone-simply-7/ |
|