iOS內(nèi)存管理系列3之 __strong,__weak等對象所有權(quán)修飾符的深入理解

__strong##

strong 修飾符是oc對象的默認修飾符,一般我們在生成一個對象的時候就默認添加了strong修飾,例如:

id arr = [[NSArray alloc] init]  等同于 id __strong arr = [[NSArray alloc] init]

strong修飾符表示對對象的強引用,那么什么是強引用,什么是弱引用,其實這些都是編譯器層面的特性,與實際的內(nèi)層方面沒有太大的關(guān)系,編譯器在處理使用strong修飾符修飾的變量和在處理使用weak修飾符修飾的變量的機制是不一樣的。持有強引用的變量在超出其作用域時會被釋放掉,強引用失效,那么其引用的對象也會隨之被廢棄掉。如下面這兩段代碼也是相等的關(guān)系:

  {
        //自己生成的對象自己持有
        id __strong arr = [[NSArray alloc] init];
        NSLog(@"%@",arr);//輸出對象內(nèi)存地址
    }//變量arr超出其作用域,強引用失效,所以其引用的對象[[NSArray alloc] init] 被廢棄
   
    {
        id arr = [[NSArray alloc] init];
        [arr release];//調(diào)用release方法直接廢棄對象
        NSLog(@"%@",arr); //輸出nil
    }

當然如果用strong去修飾的是非自己生成并持有的對象,只要超出變量的作用域其結(jié)果就跟上面的一樣。
在strong修飾符修飾的對象之間可以相互進行賦值操作,賦值之后新變量也是strong類型,原變量被廢棄。原變量所引用的對象也隨之被廢棄,原變量與新變量指向同一塊內(nèi)存空間例如:

    {
        id __strong obj1 = [[NSObject alloc] init];

        id __strong obj2 = [[NSObject alloc] init];
       
        id __strong obj3 = nil;

        obj1 = obj2;
        
        NSLog(@"%@ -- %@",obj1,obj2);//輸出 <NSObject: 0x600000012b70> -- <NSObject: 0x600000012b70>
        
        obj3 = obj1;
        NSLog(@"%@ -- %@",obj3,obj1); //輸出 <NSObject: 0x600000012b70> -- <NSObject: 0x600000012b70>
        
    }

通過上面的例子可以看到,__strong修飾的變量不僅僅只在變量作用域中,在賦值上一樣的可以管理其對象的所有者。
正如蘋果說的。通過strong修飾符,人們就可以不用去輸入retain和release代碼也可以正確的管理內(nèi)存,這就是使用引用計數(shù)來管理內(nèi)存的思考方式:
1,自己生成的對象自己所持有,
2,非自己生成的對象自己也能持有,
3,不再需要自己持有的對象時釋放,
4,非自己持有的對象無法釋放。

只需要通過對帶strong修飾符的變量賦值就可以達到 前兩項自己生成的對象自己持有和非自己生成的對象自己也能持有的效果, 通過廢棄帶strong修飾符的變量(變量作用域結(jié)束或是成員變量所屬對象廢棄)或者對變量賦值都可以做到 不再需要自己持有的對象時釋放。 最后一項 非自己持有的對象無法釋放 因為 不必再次鍵入release,所以原本就不會執(zhí)行,這些都滿足引用計數(shù)式內(nèi)存管理的思考方式。

__weak##

使用strong 修飾變量的時候我們會發(fā)現(xiàn)一個問題,比如下面這段代碼:

//測試代碼
@interface Test : NSObject

@property(nonatomic, strong)id obj;

@end

@implementation Test
-(id)init{
    self = [super init];
    return self;
}
-(void)setObj:(id)obj{
    _obj = obj;
}
@end

{
    Test *test0 = [[Test alloc] init]; //A對象
    Test *test1 = [[Test alloc] init];//B對象
    
    //此時B對象的持有者為test1 和 A對象的成員變量obj,B對象被兩條強指針指向
    [test0 setObj:test1];
    
    //此時A對象的持有者為test0 和 B對象的成員變量obj,A對象被兩條強指針指向
    [test1 setObj:test0];
}
    /*
     test0 超出其作用域 ,所以其強引用失效,自動釋放對象A;
     test1 超出其作用域 ,所以其強引用失效,自定釋放對象B;
     
     此時持有象A的強引用的變量為B對象的成員變量obj;
     此時持有對象B的強引用的變量為A對象的成員變量obj;
     
     因為都還被一條強指針指向,所以內(nèi)存泄漏!
    */

從上面的代碼可以看出,對象B本該在超過作用域后釋放的,但是A對象的成員變量obj一直強引用著它,對象B的引用計數(shù)一直不能減為0,所以導致對象B一直無法釋放,對象A也是一樣,也因為被對象B的成員變量obj強引用所以也一直無法釋放,這兩個對象就像一只咬住自己尾巴的蛇進入了死鎖狀態(tài)導致這兩塊內(nèi)存無法被回收,從而發(fā)生內(nèi)存泄漏。大家可以好好體會下。

那么要解決上面這個問題,該怎么辦,顯然蘋果已經(jīng)考慮到了,那就是引入弱引用__weak。它跟strong的區(qū)別就是它不能持有對象的實例,比如:

id __weak obj = [[NSObject alloc] init];//對象A

已寫完這行代碼編譯器就會發(fā)生警告:


D5CDF41C-DEA3-408B-978E-7C9265FD9CD6.png

在沒有任何賦值的時候。對象A一被創(chuàng)建就會馬上被釋放。寫成下面這樣就不會了:

{
    id __weak obj = [[NSObject alloc] init];
    id __strong obj1 = obj;
}

因為使用weak修飾的變量不能持有對象的實例,所以在MRC下也就意味著引用計數(shù)不會加1,所以內(nèi)存可以被正確回收。

下面再來看下__weak的另一種好處:

id __weak obj = @;
    {
        Test *obj1 = [[Test alloc] init];// 對象A
        obj1 = obj;
        NSLog(@"obj1 = %@",obj1);//輸出 obj1 = <Test: 0x600000018be0>
    }
        NSLog(@"obj = %@",obj);輸出 0bj = (null)

從以上代碼可以看出在持有某對象的弱引用時,弱該對象被廢棄了,那么此弱引用將自動失效且弱引用修飾的變量自動置為nil。
像這樣,使用__weak修飾符可以很好地避免循環(huán)引用的出現(xiàn),這也是我們在block里面使用weakSelf 而不使用self 的原因,因為block會捕獲self,而self又持有block,導致兩個互相指向從而發(fā)生內(nèi)存泄漏,代理也是一樣也要用weak修飾來避免循環(huán)引用。
那么如果項目中已經(jīng)發(fā)生了循環(huán)引用的話我們應該如何來排查呢,請關(guān)注我的下一篇文章,我會教你如何查出項目中哪些地方發(fā)生了循環(huán)引用。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,936評論 6 535
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,744評論 3 421
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,879評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,181評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,935評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,325評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,384評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,534評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,084評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,892評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,067評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,623評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,322評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,735評論 0 27
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,990評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,800評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,084評論 2 375

推薦閱讀更多精彩內(nèi)容