1.3 ARC規(guī)則
1.3.1 概要
實際上“引用計數(shù)式內存管理”的本質部分在ARC中并沒有改變润脸。就像“自動引用計數(shù)”這個名稱表示的那樣,幫我們自動處理“引用計數(shù)”的相關部分。
1.3.2 內存管理的思考方式
和之前的章節(jié)所描述一樣
- 自己生成的對象耐量,自己持有
- 非自己生成的對象,也能持有
- 自己持有的對象不再需要時釋放
- 非自己持有的對象無法釋放
1.3.3 所有權修飾符
一共四種
- __strong 修飾符
- __weak 修飾符
- __unsafe_unretained 修飾符
- __autoreleasing 修飾符
__strong 修飾符
__strong 修飾符是 id 類型和對象默認的所有權修飾符。
__strong 修飾符表示對對象的“強引用”扫尺,修飾的對象在超出其作用域后自動釋放其持有的對象。
__strong 所修飾的變量可以相互賦值
循環(huán)引用:兩個__strong修飾的變量互相持有炊汤,引發(fā)內存泄漏
內存泄漏:超出作用域的對象無法廢棄正驻,繼續(xù)存在
__weak 修飾符
__weak 修飾符修飾的變量只獲取對象的弱引用,不持有對象
id __weak obj0 = [[NSObject alloc] init];
是不對的抢腐。姑曙。。
正確的寫法
id __strong obj0 = [[NSObject alloc] init];
id __weak obj1 = obj0;
原因是 alloc 生成的對象默認是自己持有迈倍,而__weak修飾符則表示只獲取對象的引用而不持有伤靠,所以生成的對象會被立即釋放。
__unsafe_unretained修飾符
id __weak obj0= nil;
id __unsafe_unretained obj1= nil;
{
id __strong obj2 = [[NSObject alloc] init];
obj0 = obj2;
obj1 = obj2;
NSLog(@“obj0: %@, obj1: %@”, obj0, obj1)
} /*
*obj2作用域結束啼染,強引用失效宴合,自動釋放對象
*此時重復輸出obj2所引用對象的地址
*/
NSLog(@“obj0: %@, obj1: %@”, obj0, obj1)
/*
*此時會輸出 nil和obj2引用的對象
*
*此時的obj2早已廢棄,所以obj1是懸垂指針迹鹅,會導致錯誤訪問導致崩潰
*/
然而卦洽,在iOS4之前,必須使用 __unsafe_unretained 來扮演 __weak 修飾符的角色斜棚。然而上述代碼出現(xiàn)的問題告訴我們阀蒂,在使用 __unsafe_unretained 修飾符時该窗,賦值給 __strong 修飾的變量時一定要確認被賦值的對象確實存在!
__autoreleasing 修飾符
在ARC有效時把對象賦值給 __autoreleasing 修飾的對象時蚤霞,相當于在 ARC 無效時對象調用 autorelease 方法酗失,即將對象注冊到 autoreleasepool 。
編譯器會檢查方法名是否以 alloc/new/copy/mutableCopy 開始昧绣,如果不是則自動將返回值的對象注冊到 autoreleaspool 规肴。init 方法的返回值的對象不注冊到 autoreleasepool 。
同時如果變量搶引用對象作為返回值時夜畴,作用域結束時該強引用所持有的對象將會自動釋放奏纪,但是作為返回值不會廢棄,而是自動注冊到 autoreleasepool 斩启。
__weak 修飾的變量序调,實際上必定要訪問注冊到 autoreleasepool的對象。
id __weak obj1 = obj0;
NSLog(@“class = %@”, [obj1 class]);
此源碼等價于
id? __weak obj1 = obj0;
id? __autoreleasing temp = obj1;
NSLog(@“class = %@”, [temp class]);
這是因為 __weak 修飾的變量只獲取對象的弱引用而不持有對象兔簇,為了確保在調用的時候對象不被廢棄发绢,使用 __autoreleasing 修飾符將對象注冊到 autoreleasepool 中。因此每次我們用 __weak 修飾符時一定會用到 autoreleasepool 中的對象垄琐。
至于對象指針默認用 __autoreleasign 修飾边酒。。狸窘。恕我愚鈍墩朦,些許弄不懂。我打開xCode實驗了下
- (void)makeAnError:(NSError *)error {
error = [[NSError alloc] init];
}
- (void)makeAnError:(NSError **)error {
*error = [[NSError alloc] init];
}
創(chuàng)建一個NSError類型的變量翻擒,指向nil氓涣,將其分別傳入兩個方法后,前者 error = 0x00,后者會有值陋气。我的問題是劳吠,在這兩個方法里創(chuàng)建出來的 error 對象注冊到 pool 里,那么此 pool 到底是哪個 pool巩趁,這個 pool 什么時候 drain痒玩,或者說在程序運行中這個 pool 的范圍到底什么多大 。為什么在 這個 error 的作用域外议慰,別的變量也可以持有蠢古。此坑待填。假如有懂的可以留言解釋下别凹,多謝草讶。
NSRunloop無論在ARC有效還是無效時都可以釋放注冊到 autoreleasepool 中的對象