做過iOS開發(fā)的都知道 strong患膛、autoreleasing修飾符袁波,對(duì)weak可能就更熟悉了导街。
筆者最近看書披泪,才發(fā)現(xiàn)對(duì)__weak修飾符的理解并不是很準(zhǔn)確。
我之前的理解:
id __weak obj = [[NSObject alloc] init];
/* 編譯器的模擬代碼 */
id obj;
id tmp = obj_msgSend(NSObject, @selector(alloc));
objc_msgSend(tmp, @selector(init));
objc_initWeak(&obj, tmp);
objc_release(tmp);
objc_destoryWeak(&obj);
weak修飾的參數(shù)在賦值的時(shí)候引用計(jì)數(shù)是不加一的搬瑰,所以在 obj = anyObject 的情況下款票,如果anyObject的引用計(jì)數(shù)不等于0的情況下,obj 是指向 &anyObject泽论。
當(dāng)anyObject的引用計(jì)數(shù)為0的時(shí)候艾少,這個(gè)時(shí)候obj就會(huì)自動(dòng)的 obj = nil。
obj并不能持有對(duì)象翼悴,所以在指向的這個(gè)對(duì)象被釋放的時(shí)候缚够,編譯器執(zhí)行 obj = nil。
我在這里的理解有一些偏差鹦赎,我認(rèn)為obj是永遠(yuǎn)都不會(huì)注冊(cè)到autoreleasepool的谍椅。(事實(shí)上并不是永遠(yuǎn))
書本上的原話:
若附有 __weak 修飾符的的變量所引用的對(duì)象被廢棄,則將 nil 賦值給該變量古话。
使用附有 __weak 修飾符的變量雏吭,即是使用注冊(cè)到 autoreleasepool 中的對(duì)象。
實(shí)際的情況:
weak修飾的變量 在使用的時(shí)候 有注冊(cè)到autoreleasepool陪踩。
id __weak obj1 = obj; // 這里的obj是 __strong 修飾的變量
NSLog(@"%@", obj1);
/* 編譯器的模擬代碼 */
id obj1;
objc_initWeak(&obj1, obj);
// ----在這里回車杖们,讀者會(huì)更好理解----
id tmp = objc_loadWeakRetained(&obj);
objc_autorelease(tmp);
NSLog(@"%@", tmp);
objc_destoryWeak(&obj1);
我們可以看到
- objc_loadWeakRetained 函數(shù)取出附有 __weak 修飾符變量所引用的對(duì)象并 retain。
- objc_autorelease 函數(shù)將對(duì)象注冊(cè)到 autoreleasepool 中膊毁。
總結(jié):
id __weak obj = [[NSObject alloc] init]; // obj這個(gè)參數(shù)一被賦值馬上被釋放
// 在 obj 釋放之前胀莹,obj1 != nil。
id __weak obj1 = obj;
// 可以理解為婚温,編譯器使用weak修飾的變量時(shí)描焰,需要先轉(zhuǎn)為strong修飾再調(diào)用。
// 每次使用到obj1的時(shí)候都會(huì)生成一個(gè) id tmp 指向 &obj栅螟。(id tmp 默認(rèn)為__strong)
// 所以這里生成的 id tmp 會(huì)導(dǎo)致 &obj 的引用計(jì)數(shù)+1
NSLog(@"%@", obj1);
id __weak obj1 = obj;
NSLog(@"1 %@", obj1);
NSLog(@"2 %@", obj1);
NSLog(@"3 %@", obj1);
NSLog(@"4 %@", obj1);
NSLog(@"5 %@", obj1);
// 變量 obj1 所賦值的對(duì)象注冊(cè)到 autoreleasepool 5次荆秦。
id __weak obj1 = obj;
id tmp = obj1;
NSLog(@"1 %@", tmp);
NSLog(@"2 %@", tmp);
NSLog(@"3 %@", tmp);
NSLog(@"4 %@", tmp);
NSLog(@"5 %@", tmp);
// 對(duì)象僅登錄到 autoreleasepool 1次