__weak修飾符詳解

??? 僅通過 __strong 是無法解決程序中的重大問題的。所說的重大問題就是引用計數(shù)式內(nèi)存管理中所必然發(fā)生的“循環(huán)引用”問題。

??? 例如:

{

??? id test0 = [[Test alloc] init];

??? id text1 = [[Test alloc] init];

??? [test0 setObject:test1];

??? [test1 setObject:test0];

}

??? 以下為持有對象狀態(tài):

{

? ? id test0 = [[Test alloc] init]; // 對象 A

// etst0 持有 Test 對象 A 的強引用

? ? id text1 = [[Test alloc] init]; // 對象 B

// test1 持有對象 B 的強引用

? ? [test0 setObject:test1];

// Test 對象 A 的 obj_ 成員變量持有 Test 對象 B 的強引用。此時,持有 Test 對象 B 的強引用的變量為 Test 對象 A 的 obj_ 和 test1.

? ? [test1 setObject:test0];

// Test 對象 B 的 obj_ 成員變量持有 Test 對象 A 的強引用。此時,持有 Test 對象 A 的強引用的變量為 Test 對象 B 的 obj_和 test0.

}

// 因為 test0 變量超出其作用域,強引用失效,所以自動釋放 Test 對象 A 。
//因為 test1 變量超出其作用域,強引用失效,所以自動釋放 Test 對象 B。
// 此時,持有Test 對象 A 的強引用的變量為 Test 對象 B 的 obj_。
// 此時,持有Test 對象 B 的強引用的變量為 Test 對象 A 的 obj_。
// 發(fā)生內(nèi)存泄漏

??? 循環(huán)引用容易發(fā)生內(nèi)存泄漏。所謂的內(nèi)存泄漏就是應(yīng)當(dāng)廢棄的對象在其作用域之外繼續(xù)存在。

??? 此代碼的本意是賦予變量 test0 的對象 A 和賦予變量 test1 的對象 B 在超出其變量作用域時被釋放,即在對象不被任何變量持有的狀態(tài)下予以廢棄。但是,循環(huán)引用使得對象不能被再次廢棄。

??? 以下情況,雖然只有一個對象,也會出現(xiàn)循環(huán)引用:

id test = [[Test alloc] init];

[test setObject:test];

?? 使用 __weak 修飾符可以避免循環(huán)引用。

??? __weak 修飾符與 __strong 修飾符相反,提供弱引用,弱引用不能持有對象實例。

id __weak obj = [[NSObject alloc] init];

??? 變量 obj 上附加了 __waek 修飾符。實際上如果編譯以上代碼,編譯器會發(fā)出警告。

??? 此源代碼將自己生成并持有的對象賦值給附有 __weak 修飾符的變量 obj。即變量 obj 持有對持有對象的弱引用。因此,為了不以自己持有的狀態(tài)來保存自己生成并持有的對象,生成的對象會立即被釋放。編譯器對此會給出警告。如果像下面這樣,將對象賦值給附有 __strong 修飾符的變量之后再賦值給附有 __weak 修飾符的變量,就不會有警告了。

{

??? id __strong obj0 = [[NSObject alloc] init];

??? id __weak obj1 = obj0;

}

??? 下面為對象持有情況:

{

?// 自己生成并持有對象

??? id __strong obj0 = [[NSObject alloc] init];

// 因為 obj0 變量為強引用,所以自己持有對象

??? id __weak obj1 = obj0;

// obj1變量持有生成對象的弱引用

} /* 因為 obj0 變量超出其作用域,強引用失效,所以自動釋放自己持有的對象。因此對象的所有者不存在,所以廢棄該對象 */

??? 因為帶 __weak 修飾符的變量(即弱引用)不持有對象,所以在超出其變量作用域時,對象即被釋放。如果像以下內(nèi)容將可能發(fā)生循環(huán)引用的類成員變量改成附有 __weak 修飾符的成員變量的話,該現(xiàn)象是可以避免的。

@inerface Test : NSObject

{

??? id __weak obj_;

}

- (void)setObject:(id __strong)obj;

@end

??? _weak 修飾符還有另一優(yōu)點。在持有某對象的弱引用時,若該對象被廢棄,則此弱引用自動失效且處于 nil 被賦值的狀態(tài)。如下:

id __weak obj1 = nil;

{

??? id __strong obj0 = [[NSObject alloc] init];

??? obj1 = obj0;

??? NSLog(@"A: %@", obj1);

}

NSLog(@"B: %@", obj1);

??? 此源碼執(zhí)行效果如下:

A:<NSObject: 0x753e180>

B: (null)

??? 以下為對象持有情況

id __weak obj1 = nil;

{

// 自己生成并持有對象

??? id __strong obj0 = [[NSObject alloc] init];

// 因為 obj0 變量為強引用,所以自己持有對象

??? obj1 = obj0;

// obj1 變量持有對象的弱引用

??? NSLog(@"A: %@", obj1);

// 輸出 obj1 變量持有的弱引用對象

}

/* 因為 obj0 變量超出其作用域,強引用失效,所以自動釋放自己持有的對象。因為對象無持有者,所以廢棄該對象。廢棄對象的同時,持有該對象弱引用的 obj1變量的弱引用失效,nil 賦值飛 obj1 */

NSLog(@"B: %@", obj1);

// 輸出賦值給 obj1 變量中的 nil

??? 像這樣,使用 __weak 修飾符可避免虛幻引用,通過檢查附有 _weak 的變量是否為 nil,可以判斷被賦值的對象是否已廢棄。




// 結(jié)束,是另一種開始。

// 作者會將所讀所學(xué)摘錄及分享

// 本文參考《Objcetive-C高級編程iOS與OS X多線程和內(nèi)存管理》

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容