《Objective-C高級(jí)編程》自動(dòng)引用計(jì)數(shù) 閱讀筆記系列
《Objective-C高級(jí)編程》自動(dòng)引用計(jì)數(shù) 閱讀筆記 item1(內(nèi)存管理/引用計(jì)數(shù))
《Objective-C高級(jí)編程》自動(dòng)引用計(jì)數(shù) 閱讀筆記 item2(ARC規(guī)則及其實(shí)現(xiàn))
1.3 ARC規(guī)則
1.3.1 設(shè)置ARC有效的編譯方法如下:
- 使用clang(LLVM編譯器)3.0或以上版本
- 指定編譯器屬性為"-fobjc-arc"
1.3.2 引用計(jì)數(shù)式內(nèi)存管理的思考方式就是在ARC有效時(shí)同樣適用
1.3.3 所有權(quán)修飾符
概念
對(duì)象類型:*** 指向NSObject這樣的Objective-C類的指針,如“NSObject * ”咱旱。 **
id類型:*** 用于隱藏對(duì)象類型的類名部分乘寒,相當(dāng)于C語(yǔ)言中的“void *”祖凫。 **
ARC有效時(shí)摔癣,對(duì)象類型和id類型必須附加所有權(quán)修飾符楞捂,如下:
- __strong修飾符
- __weak修飾符
- __unsafe_unretained修飾符
- __autoreleasing修飾符
*** __strong修飾符 ***
__strong修飾符是id類型和對(duì)象類型默認(rèn)的所有權(quán)修飾符烧给。
源碼如下:
{
id __strong obj = [[NSObject alloc] init];
}
附有__strong修飾符的變量obj在超出其變量作用域時(shí)梁丘,即在該變量被廢棄時(shí)侵浸,會(huì)釋放其被賦予對(duì)象。
關(guān)鍵知識(shí)點(diǎn):
- __strong修飾符表示對(duì)對(duì)象的”強(qiáng)引用“氛谜。持有強(qiáng)引用的變量在超出其作用域時(shí)被廢棄掏觉,隨著強(qiáng)引用的失效,引用的對(duì)象會(huì)隨之釋放混蔼。
- 附有__strong修飾符的變量之間可以相互賦值履腋。通過(guò)相互賦值,可以使得變量對(duì)對(duì)象的強(qiáng)引用失效惭嚣,從而釋放原先持有的對(duì)象遵湖,轉(zhuǎn)而持有由另外一個(gè)變量賦值的新的對(duì)象的強(qiáng)引用。
- 即時(shí)是Objective-C類成員變量晚吞,也可以在方法參數(shù)上延旧,使用附有__strong修飾符的變量
- __strong修飾符可以確保將附有__strong修飾符的自動(dòng)變量(局部變量)初始化為nil(該規(guī)則適用于__weak修飾符和__autoreleasing修飾符)
*** 通過(guò)__strong修飾符使ARC有效遵循了Objective-C內(nèi)存管理的思考方式 ***
- “自己生成的對(duì)象,自己持有”和“非自己生成的對(duì)象槽地,自己也能持有”只需通過(guò)對(duì)帶__strong修飾符的變量賦值便可達(dá)成
- 通過(guò)廢棄帶__strong修飾符的變量(變量作用域結(jié)束或是成員變量所屬對(duì)象廢棄)或者對(duì)變量賦值迁沫,都可以做到”不再需要自己持有的對(duì)象時(shí)釋放“
- 由于不必再次鍵入release,所以”非自己持有的對(duì)象無(wú)法釋放“原本就不會(huì)執(zhí)行
__strong修飾符的不足
__strong修飾符無(wú)法解決引用計(jì)數(shù)式內(nèi)存管理中存在的問(wèn)題——循環(huán)引用捌蚊。循環(huán)引用容易發(fā)生內(nèi)存泄露(內(nèi)存泄露:應(yīng)當(dāng)廢棄的對(duì)象在超出其生存周期后繼續(xù)存在)集畅。
- 類成員變量的循環(huán)引用:
- 自引用:
*** __weak修飾符 ***
__weak修飾符提供弱引用。弱引用不能持有對(duì)象缅糟。
{
id _weak obj = [[NSObject alloc] init];
}
實(shí)際編譯以上代碼挺智,編譯器會(huì)報(bào)錯(cuò),如下:
解釋:將自己生成并持有的對(duì)象賦值給帶__weak修飾符的變量obj窗宦,變量obj會(huì)立即釋放生成的對(duì)象赦颇。
解決方式:將對(duì)象賦值給附有__strong修飾符的變量之后再賦值給附有__weak修飾符的變量二鳄,如下:
{
id __strong obj0 = [[NSObject alloc] init];
id __weak obj1 = obj0;
}
由于帶__weak修飾符的變量(弱引用)不持有對(duì)象,所以超出其變量作用域時(shí)媒怯,對(duì)象即被釋放订讼。
__weak修飾符的優(yōu)點(diǎn)
-
可以避免發(fā)生循環(huán)引用
- 在持有“對(duì)象”的弱引用時(shí),若該對(duì)象被廢棄扇苞,則此弱引用將自動(dòng)失效且處于nil被賦值的狀態(tài)(空弱引用)欺殿,如以下代碼:
id __weak obj1 = nil;
{
id __strong obj0 = [[NSObject alloc] init];
obj1 = obj0; // obj1變量持有NSObject對(duì)象的弱引用
NSLog(@“A : %@”, obj1);
// output A : <NSObject: 0x731e180>
}
NSLog(@“B : %@”, obj1; // output B : (null)
- 通過(guò)檢查附有__weak修飾符的變量是否為nil,可以判斷被賦值的對(duì)象是否已廢棄
- __weak修飾符只能用于iOS5以上及OS X Lion以上版本的應(yīng)用程序
*** __unsafe_unretained修飾符 ***
源代碼分析:
id __unsafe_unretained obj1 = nil;
{
id __strong obj0 = [[NSObject alloc] init];
obj1 = obj0;
// obj1變量即不持有對(duì)象的強(qiáng)引用也不持有弱引用
NSLog(@"A: %@", obj1);
// 輸出obj1變量表示的對(duì)象
}
/*
* 因?yàn)閛bj0變量超出其作用域鳖敷,強(qiáng)引用失效祈餐,
* 所以自動(dòng)釋放自己持有的對(duì)象
* 因?yàn)閷?duì)象無(wú)持有者,所以廢棄該對(duì)象
*/
NSLog(@"B: %@", obj1);
/*
* 輸出obj1變量表示的對(duì)象
*
* obj1表示的對(duì)象已經(jīng)被廢棄(懸垂指針)哄陶!
* 錯(cuò)誤訪問(wèn)!
*/
- 附有 __unsafe_unretained修飾符的變量不屬于編譯器的內(nèi)存管理對(duì)象哺壶。
- 附有__unsafe_unretained修飾符的變量同附有__weak修飾符的變量一樣屋吨,因?yàn)樽约荷刹⒊钟械膶?duì)象不能繼續(xù)為自己所有,所以生成的對(duì)象會(huì)立即被釋放山宾。
- 訪問(wèn)了已經(jīng)被廢棄的對(duì)象至扰,只有在個(gè)別運(yùn)行情況下應(yīng)用程序才會(huì)崩潰。
- 在使用__unsafe_unretained修飾符時(shí)资锰,賦值給附有__strong修飾符的變量時(shí)有必要確保被賦值的對(duì)象確實(shí)存在
- 賦值給附有__unsafe_unretained修飾符變量的對(duì)象在通過(guò)該變量使用時(shí)敢课,如果沒有確保其確實(shí)存在,那么應(yīng)用程序就會(huì)崩潰
*** __autoreleasing修飾符 ***
-
在ARC有效時(shí)绷杜,用@autoreleasepool塊替代NSAutoreleasePool類直秆,用附有_autoreleasing修飾符的變量替代autorelease方法,如下:
- 不需要顯式地附加__autoreleasing修飾符鞭盟,因?yàn)榫幾g器會(huì)檢查方法名是否已a(bǔ)lloc/new/copy/mutableCopy方法開始圾结,如果不是則自動(dòng)將返回值的對(duì)象注冊(cè)到autoreleasePool。
@autoreleasePool{
id __strong obj = [NSMutableArray array];
/*
* obj變量持有對(duì)象的強(qiáng)引用
*
* 并且該對(duì)象由編譯器判斷其方法名后齿诉,
* 自動(dòng)注冊(cè)到autoreleasePool
*/
}/*
* obj變量超出其作用域筝野,強(qiáng)引用失效
* 所以自動(dòng)釋放自己持有的對(duì)象
*
* 同時(shí),隨著@autoreleasePool塊的結(jié)束粤剧,
* 注冊(cè)到autoreleasePool中的所有對(duì)象被自動(dòng)釋放
*
* 因?yàn)閷?duì)象的所有者不存在歇竟,所以廢棄該對(duì)象
*/
- 訪問(wèn)附有__weak修飾符的變量時(shí),實(shí)際上必定要訪問(wèn)注冊(cè)到autoreleasePool的對(duì)象抵恋。
- id的指針或?qū)ο蟮闹羔樤跊]有顯式指定時(shí)會(huì)被附加上_autoreleasing修飾符焕议,如下:
指針 | 帶__autoreleasing修飾符 |
---|---|
id的指針id *obj | id __autoreleasing *obj |
對(duì)象的指針NSObject **obj | NSObject *__autoreleasing *obj |
- 為了得到詳細(xì)的錯(cuò)誤信息,經(jīng)常在方法的參數(shù)中傳遞NSError對(duì)象的指針馋记,而不是函數(shù)返回值号坡。
// 方法聲明
- (Bool)performOperationWithError:(NSError **)error;
// 等同于
- (Bool)performOperationWithError:(NSError *__autoreleasing *)error;
// 應(yīng)用
NSError *error = nil;
Bool result = [obj performOperationWithError:&error];
// 上述源代碼經(jīng)過(guò)編譯器的轉(zhuǎn)化:
NSError __strong *error = nil;
NSError __autoreleasing *tmp = error;
Bool result = [obj performOperationWithError:&tmp];
error = tmp;
/*
編譯器正是通過(guò)這種添加源代碼的方式使得原先的源代碼即不會(huì)編譯出錯(cuò)懊烤,也能在使用 參數(shù)取得對(duì)象時(shí),貫徹內(nèi)存管理的思考方式宽堆。
*/
- 在顯式地指定__autoreleasing修飾符時(shí)腌紧,必須注意對(duì)象變量要為自動(dòng)變量(包括局部變量、函數(shù)以及方法參數(shù))
1.3.4 ARC的規(guī)則
- 不能使用retain/release/retainCount/autorelease
- 不能使用NSAllocateObject/NSDeallocateObject
- 須遵守內(nèi)存管理的方法命名規(guī)則
- 不要顯式調(diào)用dealloc
- 使用@autoreleasePool替代NSAutoreleasePool
- 不能使用區(qū)域(NSZone)
- 對(duì)象型變量不能作為C語(yǔ)言結(jié)構(gòu)體(struct/union)的成員
- 顯式轉(zhuǎn)換“id”和“void”
*** 須遵守內(nèi)存管理的方法命名規(guī)則 ***
在ARC有效時(shí)畜隶,用于對(duì)象生成/持有的方法除了alloc/new/copy/mutableCopy還要追加一條命名規(guī)則init壁肋。
該方法是實(shí)例方法,并且必須要返回對(duì)象籽慢。返回的對(duì)象應(yīng)為id類型或該方法聲明類的對(duì)象類型浸遗,或是該類的超類型或子類型。該返回對(duì)象并不注冊(cè)到autoreleasePool上箱亿□诵浚基本上只是對(duì)alloc方法返回值的對(duì)象進(jìn)行初始化處理并返回該對(duì)象。
*** 不要顯式調(diào)用dealloc ***
- 對(duì)象被廢棄時(shí)届惋,不管ARC是否有效髓帽,都會(huì)調(diào)用對(duì)象的dealloc方法。在dealloc方法里記述廢棄對(duì)象時(shí)所需做的處理脑豹。
- dealloc方法需要通過(guò)free來(lái)釋放留出的內(nèi)存郑藏。
- dealloc方法在大多數(shù)情況下適用于刪除已注冊(cè)的代理或觀察者對(duì)象。
*** 對(duì)象型變量不能作為C語(yǔ)言結(jié)構(gòu)體(struct/union)的成員 ***
要把對(duì)象型變量加入到結(jié)構(gòu)體成員中時(shí)瘩欺,可強(qiáng)制轉(zhuǎn)換為void * 或是附加__unsafe_unretained修飾符
*** 顯式轉(zhuǎn)換“id”和“void” ***
- id類型或?qū)ο箢愋妥兞抠x值給void *或者逆向賦值時(shí)都需要進(jìn)行特定的轉(zhuǎn)換必盖。如果只想單純地賦值,則可以使用"__bridge轉(zhuǎn)換"俱饿。如void *p = (__bridge void *)obj;
- __bridge_retained轉(zhuǎn)換可使要轉(zhuǎn)換賦值的變量也持有所賦值的對(duì)象歌粥。與retain類似。
void *p = 0;
{
id obj = [[NSObject alloc] init]; // 對(duì)象的retaidedCount : 1
p = (__bridge_retained void *)obj; // 對(duì)象的retainedCount : 2
}
// 作用域結(jié)束時(shí)稍途,obj變量持有對(duì)象的強(qiáng)引用失效阁吝,所以釋放持有對(duì)象,但是由于__bridge_retained轉(zhuǎn)換使變量p看上去處于持有該對(duì)象的狀態(tài)械拍,因此該對(duì)象不會(huì)被廢棄
NSLog(@"class = %@", [(__bridge id)p class]);
- __bridge_transfer突勇,被轉(zhuǎn)換的變量所持有的對(duì)象在該變量被賦值給轉(zhuǎn)換目標(biāo)變量后隨之釋放。與release類似坷虑。
- 這些轉(zhuǎn)換多數(shù)使用在Objective-C對(duì)象和Core Foundation對(duì)象之間的相互變換中甲馋。
1.3.5 屬性
當(dāng)ARC有效時(shí),屬性聲明的屬性與所有權(quán)修飾符的對(duì)應(yīng)關(guān)系迄损,如下表:
屬性聲明的屬性 | 所有權(quán)修飾符 |
---|---|
assign | __unsafe_unretained修飾符 |
copy | __strong修飾符(但是賦值的是被復(fù)制的對(duì)象) |
retain | __strong修飾符 |
strong | __strong修飾符 |
unsafe_unretianed | __unsafe_unretained修飾符 |
weak | __weak修飾符 |
1.3.6 數(shù)組
__unsafe_unretained修飾符以外的__strong/__weak/__autoreleasing修飾符保證其指定的變量初始化為nil定躏。同樣地,附有__strong/__weak/__autoreleasing修飾符變量的數(shù)組也保證其初始化為nil。如下痊远,將附有__strong修飾符的變量作為靜態(tài)數(shù)組使用:id objs[10];
將附有__strong修飾符的變量作為動(dòng)態(tài)數(shù)組使用時(shí)垮抗,根據(jù)不同的目的選擇使用NSMutableArray、NSMutableDictionary碧聪、NSMutableSet等Foundation框架的容器冒版。這些容器會(huì)恰當(dāng)?shù)爻钟凶芳拥膶?duì)象并為我們管理這些對(duì)象。
-
在C語(yǔ)言的動(dòng)態(tài)數(shù)組使用附有__strong修飾符的變量逞姿,必須遵守一些事項(xiàng):
- 聲明動(dòng)態(tài)數(shù)組用指針,如id __strong *array = nil;由于不能保證附有__strong修飾符的id指針類型變量被初始化為nil辞嗡,需要自行賦值nil。
- 使用類名時(shí)如下滞造,NSObject *__strong *array = nil;
使用calloc函數(shù)確保想分配的附有__strong修飾符變量的容量占有的內(nèi)存塊续室,如array = (id __strong *)calloc(entries, sizeof(id));
在動(dòng)態(tài)數(shù)組中操作附有__strong修飾符的變量與靜態(tài)數(shù)組有很大差異,需要自己釋放所有的元素谒养。在用free函數(shù)廢棄數(shù)組用內(nèi)存塊前挺狰,需要先將nil賦值給所有元素,使得元素所賦值對(duì)象的強(qiáng)引用失效买窟,從而釋放那些對(duì)象她渴,再用free函數(shù)廢棄內(nèi)存塊。
使用附有__weak修飾符變量的動(dòng)態(tài)數(shù)組與使用__strong修飾符相像蔑祟。
在__autoreleasing修飾符的情況下,最好不要使用動(dòng)態(tài)數(shù)組沉唠。
由于__unsafe_unretained修飾符在編譯器的內(nèi)存管理對(duì)象之外疆虚,所以它與void *類型一樣,只能作為C語(yǔ)言的指針類型來(lái)使用.
1.4 ARC的實(shí)現(xiàn)
ARC由以下工具满葛、庫(kù)來(lái)實(shí)現(xiàn):
- clang(LLVM編譯器)3.0以上
- objc4 Objective-C運(yùn)行時(shí)庫(kù)493.9以上
1.4.1 __strong修飾符
{
id __strong obj = [[NSObject alloc] init];
}
以上源代碼可轉(zhuǎn)換為調(diào)用以下的函數(shù)径簿,
/* 編譯器的模擬代碼 */
id obj = objc_msgSend(NSObject, @selector(alloc));
objc_msgSend(obj, @selector(init));
objc_release(obj);
總結(jié)
如上所示,*** 在ARC有效時(shí)不能使用release方法的緣故是編譯器會(huì)自動(dòng)插入release嘀韧。***
NSMutableArray類的array類方法的調(diào)用如下:
{
id __strong obj = [NSMutableArray array];
}
轉(zhuǎn)換后的源代碼是
/* 編譯器的模擬代碼 */
id obj = objc_msgSend(NSMutableArray, @selector(array));
objc_retainAutoreleasedReturnValue(obj);
objc_release(obj);
其中篇亭,NSMutableArray類的array類方法:
+ (id) array
{
return [[NSMutableArray alloc] init];
}
轉(zhuǎn)換后的源代碼是
/* 編譯器的模擬代碼 */
+ (id) array
{
id obj = objc_msgSend(NSMutableArray, @selector(alloc));
objc_msgSend(obj, @selector(init));
return objc_autoreleaseReturnValue(obj);
}
總結(jié)
如上所示,*** objc_retainAutoreleasedReturnValue函數(shù)和objc_autoreleaseReturnValue函數(shù)的協(xié)作锄贷,可以不將對(duì)象注冊(cè)到autoreleasePool中而直接傳遞译蒂,這一過(guò)程達(dá)到了最優(yōu)化。***
如圖所示:
關(guān)鍵知識(shí)點(diǎn):
objc_autoreleaseReturnValue函數(shù)用于alloc/new/copy/mutableCopy方法以外的NSMutableArray類的array類方法等返回對(duì)象的實(shí)現(xiàn)上谊却。
objc_autoreleaseReturnValue函數(shù)與objc_autorelease函數(shù)不同柔昼,一般不僅限于注冊(cè)對(duì)象到autoreleasePool中。
objc_retainAutoreleasedReturnValue函數(shù)主要用于最優(yōu)化程序運(yùn)行形导。即干茉,它是用于自己持有(retain)對(duì)象的函數(shù)唠梨,但它持有的對(duì)象應(yīng)為返回注冊(cè)在autoreleasePool中對(duì)象的方法或是函數(shù)的返回值棵譬。
objc_retainAutoreleasedReturnValue函數(shù)與objc_retain函數(shù)不同乙嘀,它即時(shí)不注冊(cè)到autoreleasePool而返回對(duì)象末购,也能夠正確地獲取對(duì)象。
objc_autoreleaseReturnValue函數(shù)會(huì)檢查使用該函數(shù)的方法或函數(shù)調(diào)用方的執(zhí)行命令列表虎谢,如果方法或函數(shù)的調(diào)用方在調(diào)用了方法或函數(shù)后緊跟著調(diào)用objc_retainAutoreleasedReturnValue函數(shù)盟榴,那么就不將返回的對(duì)象注冊(cè)到autoreleasePool中,而是直接傳遞到方法或函數(shù)的調(diào)用方嘉冒。
1.4.2 __weak修飾符
- 若附有__weak修飾符的變量所引用的對(duì)象被廢棄曹货,則將nil賦值給該變量。
- 使用附有__weak修飾符的變量讳推,即是使用注冊(cè)到autoreleasePool中的對(duì)象顶籽。
假設(shè)obj附有__strong修飾符且對(duì)象被賦值
{
id __weak obj1 = obj;
}
轉(zhuǎn)換后的源代碼是
/* 編譯器的模擬代碼 */
id obj1;
objc_initWeak(&obj1, obj);
objc_destroyWeak(&obj1);
其中,objc_initWeak函數(shù)將附有__weak修飾符的變量初始化為0后银觅,會(huì)將賦值的對(duì)象作為參數(shù)調(diào)用objc_storeWeak函數(shù):
obj1 = 0;
objc_storeWeak(&obj1, obj);
objc_destroyWeak函數(shù)將0作為參數(shù)調(diào)用objc_storeWeak函數(shù):
objc_storeWeak(%obj1, 0);
即礼饱,轉(zhuǎn)換后的源代碼也可以是
/* 編譯器的模擬代碼 */
id obj1;
obj1 = 0;
objc_storeWeak(&obj1, obj);
objc_storeWeak(%obj1, 0);
總結(jié)
- 通過(guò)objc_initWeak函數(shù)初始化附有__weak修飾符的變量,在變量作用域結(jié)束時(shí)通過(guò)objc_destroyWeak函數(shù)釋放該變量究驴。
- objc_destroyWeak函數(shù)把第二參數(shù)的賦值對(duì)象的地址作為鍵值镊绪,將第一參數(shù)的附有__weak修飾符的變量的地址注冊(cè)到weak表中。如果第二參數(shù)為0洒忧,則把變量的地址從weak表中刪除蝴韭。
釋放對(duì)象,廢棄誰(shuí)都不持有的對(duì)象時(shí)熙侍,程序的動(dòng)作:
- objc_release
- 因?yàn)橐糜?jì)數(shù)為0所以執(zhí)行dealloc
- _objc_rootDealloc
- object_dispose
- objc_destructInstance
- objc_clear_deallocating
其中榄鉴,對(duì)象被廢棄時(shí)最后調(diào)用的objc_clear_deallocating函數(shù)的動(dòng)作如下:
- 從weak表中獲取廢棄對(duì)象的地址為鍵值的記錄
- 將包含在記錄中的所有附有__weak修飾符變量的地址,賦值為nil(釋放變量)
- 從weak表中刪除該記錄
- 從引用計(jì)數(shù)表中刪除廢棄對(duì)象的地址為鍵值的記錄(廢棄對(duì)象)
注意
- 附有__weak修飾符的變量所引用的對(duì)象被廢棄時(shí)蛉抓,則將nil賦值給該變量庆尘。如果大量使用附有__weak修飾符的變量,則會(huì)消耗相應(yīng)的CPU資源巷送。最好是只在需要避免循環(huán)引用時(shí)使用__weak修飾符驶忌。
- 將自己生成并持有的對(duì)象直接賦值給附有__weak修飾符的變量,編譯器會(huì)報(bào)錯(cuò)笑跛,如下:
{
id __weak obj = [[NSObject alloc] init];
}
obj變量不能持有該對(duì)象付魔,這時(shí)會(huì)被釋放并被廢棄,引起編譯器的警告飞蹂。
通過(guò)轉(zhuǎn)換后的源代碼解釋抒抬,
/* 編譯器的模擬代碼 */
id obj;
id tmp = objc_msgSend(NSObject, @selctor(alloc));
objc_msgSend(tmp, @selctor(init));
objc_initWeak(&obj, tmp);
objc_release(tmp); // 釋放該對(duì)象
objc_destroyWeak(&object); // 廢棄該對(duì)象
總結(jié)
- 雖然自己生成并持有的對(duì)象通過(guò)objc_initWeak函數(shù)被賦值給附有__weak修飾符的變量中,但編譯器判斷其沒有持有者晤柄,故該對(duì)象立即通過(guò)objc_release函數(shù)被釋放和廢棄擦剑。
- nil會(huì)被賦值給引用廢棄對(duì)象的附有__weak修飾符的變量中。
假設(shè)obj附有__strong修飾符且對(duì)象被賦值
{
id __weak obj1 = obj;
NSLog(@"%@", obj1);
}
轉(zhuǎn)換后的源代碼是
/* 編譯器的模擬代碼 */
id obj1;
objc_initWeak(&obj1, obj);
id tmp = objc_loadWeakRetained(&obj1);
objc_autorelease(tmp);
NSLog(@"%@", tmp);
objc_destroyWeak(&obj1);
其中,與前面的被賦值時(shí)相比惠勒,在使用附有__weak修飾符變量的情形下赚抡,增加了對(duì)objc_loadWeakRetained函數(shù)和objc_autorelease函數(shù)的調(diào)用。這兩個(gè)函數(shù)的動(dòng)作如下:
- objc_loadWeakRetained函數(shù)取出附有__weak修飾符所引用的對(duì)象并retain纠屋。
- objc_autorelease函數(shù)將對(duì)象注冊(cè)到autoreleasepool中涂臣。
注意
- 因?yàn)楦接衉_weak修飾符變量所引起的對(duì)象像這樣被注冊(cè)到autoreleasepool中,所以在@autoreleasepool塊結(jié)束之前都可以放心使用售担。
- 如果大量地使用附有__weak修飾符的變量赁遗,注冊(cè)到autoreleasepool的對(duì)象也會(huì)大量地增加,因此在使用附有__weak修飾符的變量時(shí)族铆,最好先暫時(shí)賦值給附有__strong修飾符的變量后再使用岩四。如
{
id __weak o = obj;
id tmp = o;
NSLog(@"1 %@", tmp);
NSLog(@"2 %@", tmp);
NSLog(@"3 %@", tmp);
}
1.4.3 __autoreleasing修飾符
將對(duì)象賦值給附有__autoreleasing修飾符的變量等同于ARC無(wú)效時(shí)調(diào)用對(duì)象的autorelease方法。
alloc/new/copy/mutableCopy方法群:
@autoreleasepool{
id __autoreleasing obj = [[NSObject alloc] init]
}
轉(zhuǎn)換后的源代碼是
/* 編譯器模擬代碼 */
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSObject, @selctor(alloc));
objc_msgSend(obj, @selctor(init));
objc_autorelease(obj); // 將對(duì)象添加到autoreleasepool中
objc_autoreleasePoolPop(pool);
NSMutableArray類的array類方法:
@autoreleasepool{
id __autoreleasing obj = [NSMutableArray array];
}
轉(zhuǎn)換后的源代碼是
/* 編譯器的模擬代碼 */
id pool = objc_autoreleasePoolPush();
id obj = objc_msgSend(NSMutableArray, @selctor(array));
objc_retainAutoreleasedReturnValue(obj);//用于自己持有(retain)對(duì)象
objc_autorelease(obj); // 將對(duì)象添加到autoreleasepool中
objc_autoreleasePoolPop(pool);
1.4.4 引用計(jì)數(shù)
- 由于弱引用并不持有對(duì)象哥攘,所以賦值給附有__weak修飾符的變量中也必定不會(huì)改變引用計(jì)數(shù)數(shù)值剖煌。
- 通過(guò)__autoreleasing修飾符向autoreleasepool注冊(cè)時(shí),引用計(jì)數(shù)數(shù)值會(huì)加1逝淹,但是@autoreleasepool塊結(jié)束時(shí)會(huì)釋放已注冊(cè)的對(duì)象耕姊,引用計(jì)數(shù)數(shù)值會(huì)減1。
- 不使用__autoreleasing修飾符栅葡,僅使用附有__weak修飾符聲明的變量也能將引用對(duì)象注冊(cè)到autoreleasepool中茉兰。
- 不能完全信任_objc_rootRetainCount函數(shù)取得的數(shù)值。
后記
由于該書講解知識(shí)點(diǎn)并沒有完整的實(shí)例欣簇,所以還需要再找另外的書籍或者博客進(jìn)行練習(xí)邦邦。個(gè)人更偏向于書籍,精通Objective-C第4醉蚁、5、6章有相關(guān)內(nèi)存管理和ARC方面的講解和練習(xí)鬼店。