本文的內(nèi)容包括
一摹察、所有權(quán)修飾符
二、ARC的基本規(guī)則
三弧腥、ARC的實現(xiàn)
ARC中仍然是通過引用計數(shù)來管理內(nèi)存,這個本質(zhì)沒有變桥帆。只是医增,不需要我們手動的寫代碼去管理內(nèi)存了,編譯器自動幫助我們管理“引用計數(shù)”相關(guān)的部分老虫。那么ARC是通過什么方式來幫我們管理內(nèi)存的呢叶骨?
ARC是通過編譯期和運行期兩部分來處理的:
- 編譯期,編譯器不是通過添加retain/release/autorelease這些方法张遭,而是會直接調(diào)用更底層的C語言函數(shù)(如objc_retain)邓萨。
- 運行期,ARC也包含運行期組件菊卷。比如缔恳,某些類方法返回對象前,為其執(zhí)行了autorelease操作洁闰,而大多數(shù)情況歉甚,我們會對返回的對象保留,比如:
_myPerson = [Person personWithName:@"Kobe"];
那么其實就相當(dāng)于先執(zhí)行了一個autorelease扑眉,然后又retain了一下纸泄。ARC可以在運行期檢測到這一多余的操作,也就是autorelease后緊跟retain腰素。那么會它們兩個會被改為調(diào)用objc_autoreleaseReturnValue
和objc_retainAutoreleasedReturnValue
聘裁。objc_autoreleaseReturnValue
會檢查后邊是否緊接著調(diào)用objc_retainAutoreleasedReturnValue
,如果是弓千,就不將返回的對象注冊到autoreleasepool中而直接傳遞衡便,省略了autorelasepool注冊,實現(xiàn)了最優(yōu)化洋访。
一镣陕、所有權(quán)修飾符
1. __strong修飾符
如它的名字一樣,__strong表示對對象的強引用姻政。持有強引用的變量在超出其作用域的時候被廢棄呆抑,隨著強引用的失效,引用的對象會隨之釋放汁展。
知識點:
- __strong修飾符是id類型和對象類型默認(rèn)的所有權(quán)修飾符鹊碍,所以一般不寫__strong。
- __strong和__weak和 __autoreleasing修飾符一樣善镰,可以將附有這些修飾符的自動變量初始化為nil妹萨。
2. __weak(iOS5以上才有,之前用__unsafe_unretained)
如它的名字一樣炫欺,__weak修飾符表示對對象的弱引用。不持有對象熏兄。
知識點:
- 可以避免循環(huán)引用品洛。
- 變量指向的對象被銷毀了树姨,變量也會自動置空為nil。
3. __unsafe_unretained
如它的名字一樣桥状,它是不安全的所有權(quán)修飾符帽揪。
知識點:
- 和__weak一樣表示弱引用,不持有對象辅斟,但不會置nil转晰,這也正是不安全的原因。
id __unsafe_unretained obj1 = nil;
{
id obj0 = [[NSObject alloc] init];
obj1 = obj0;
NSLog(@"A:%@",obj1);
}
NSLog(@"B:%@",obj1);
輸出A和B雖然是一樣的地址士飒,但是此時B處obj1已經(jīng)是野指針了查邢。
4. __autoreleasing
通過給對象附加__autoreleasing修飾符 來替代調(diào)用autorelease方法,把對象注冊到autoreleasepool中酵幕。
具體使用情況扰藕,在這里。
二芳撒、規(guī)則
1. 不能使用retain/release/retainCount/autorelease
2. 用@autoreleasepool{}代替NSAutoreleasePool對象
3. 不要顯式的調(diào)用dealloc
多數(shù)情況下在dealloc中刪除已注冊的代理或觀察者邓深。不用書寫[super dealloc],因為ARC已經(jīng)自動處理了笔刹。
4. 必須遵守內(nèi)存管理的方法命名規(guī)則
- alloc/new/copy/mutableCopy芥备,以上述名稱開始的方法在返回對象時,必須返回給調(diào)用方所應(yīng)當(dāng)持有的對象舌菜。這在ARC下萌壳,依然沒有變。
- ARC下追加了一條命名規(guī)則:
- init酷师,以init開頭的方法讶凉,必須是實例方法,并且返回對象山孔,類型應(yīng)為id或該類的的對象類型懂讯,抑或是超類或子類型。該方法基本上只是對alloc方法返回的對象進(jìn)行初始化操作并返回台颠。
注:initialize方法并不包含在上述命名規(guī)則里褐望。
5. 對象類型不能作為結(jié)構(gòu)體的成員
因為ARC把內(nèi)存管理的工作分配給了編譯器,所以編譯器必須能夠知道并管理對象的生命周期串前。例如C語言的自動變量(局部變量)可以使用該變量的作用域來管理瘫里。但是對于結(jié)構(gòu)體成員來說,是無法實現(xiàn)的荡碾。
6. 顯式轉(zhuǎn)換id和void*
id obj = [[NSObject alloc] init];
void *p = (__bridge void *)obj;
但是谨读,__bridge安全性與__unsafe_unretained類似,甚至更低坛吁。很容易造成野指針導(dǎo)致崩潰劳殖。
__bridge還有另外兩種轉(zhuǎn)換铐尚,__bridge_retained和__bridge_transfer
- Core Foundation 對象類型不在 ARC 管理范疇內(nèi),需要自己管理.
- __bridge只做類型轉(zhuǎn)換哆姻,但是不修改對象(內(nèi)存)管理權(quán)宣增,原來是ARC管理的還用ARC,原來MRC管理的繼續(xù)用MRC
- __bridge_retained(也可以使用CFBridgingRetain)將Objective-C的對象轉(zhuǎn)換為Core Foundation的對象矛缨,同時將對象(內(nèi)存)的管理權(quán)交給我們爹脾,后續(xù)需要使用CFRelease或者相關(guān)方法來釋放對象;
- __bridge_transfer(也可以使用CFBridgingRelease)將Core Foundation的對象轉(zhuǎn)換為Objective-C的對象箕昭,同時將對象(內(nèi)存)的管理權(quán)交給ARC灵妨。
5. 不能使用NSAllocateObject/NSDeallocObject
6. 不能使用區(qū)域(NSZone)
三、ARC的實現(xiàn)
1. __strong實現(xiàn)
賦值給附有__strong修飾符的變量在實際的程序中是怎樣運行的呢盟广?
{
id __strong obj = [[NSObject alloc] init];
}
編譯器在超出作用域時自動插入了release闷串。
{
id __strong obj = [NSMutableArray array];
}
執(zhí)行,alloc/new/copy/mutableCopy之外的方法筋量,如array類方法:
像代碼這樣烹吵,返回注冊到autoreleasepool中對象的方法使用了objc_autoreleaseReturnValue,如果其后緊接著調(diào)用objc_retainAutoreleasedReturnValue()桨武,那么就不將返回的對象注冊的autoreleasepool中而直接傳遞肋拔。通過這兩個方法,優(yōu)化了程序運行呀酸。
2.__weak的實現(xiàn)
id __strong obj = [[NSObject alloc]init];
id __weak obj1 = obj;
objc_initWeak函數(shù)中的weak_register_no_lock()把賦值對象obj的地址作為鍵值凉蜂,通過哈希查找找到weak弱引用表中對應(yīng)的數(shù)組,將附有__weak修飾符變量的指針添加到數(shù)組中性誉。如果沒有找到數(shù)組窿吩,表示是第一個weak指針,則新建一個數(shù)組错览。
對象在被廢棄時dealloc方法中會調(diào)用object_dispose函數(shù)纫雁,該方法內(nèi)部會通過調(diào)用weak_clear_no_lock()
- 通過哈希查找從weak表中獲取廢棄對象地址作為鍵值的記錄是一個數(shù)組。
- 將包含在數(shù)組中的所有附有__weak修飾符的變量地址倾哺,遍歷數(shù)組賦值為nil轧邪。
- 從weak表中刪除該記錄。
- 從weak表中刪除該鍵值羞海。
所以忌愚,如果大量使用__weak修飾符的變量,則會消耗相應(yīng)的cpu資源却邓。良策是只在需要避免循環(huán)引用的時候使用__weak硕糊。
3. __autoreleasing修飾符的實現(xiàn)
objc_autorelease
4. 引用計數(shù)
可以通過_objc_rootRetainCount(obj)來獲取對象的引用計數(shù)值。但實際上并不能完全信任該函數(shù)取得的值。對于已經(jīng)釋放的對象以及不正確的對象地址癌幕,有時也返回1衙耕。另外昧穿,在多線程中使用它勺远,因為存在競態(tài)條件的問題,所以取得的數(shù)值也不一定完全可信时鸵。當(dāng)然它在調(diào)試中還是比較有用的胶逢。