iOS內(nèi)存泄露&&檢測

內(nèi)存泄露:

一個(gè)對(duì)象被其他對(duì)象強(qiáng)引用,在本來該作用域結(jié)束之后釋放調(diào)用(dealloc),但是沒有得到釋放(dealloc未執(zhí)行).

引起內(nèi)存泄露的常見原因有哪些?

參考這篇博文 : iOS內(nèi)存泄漏的常見情況,其中最常見的應(yīng)該是對(duì)象之間相互引用,block和代理了.


序言 :

 #define TLog(prefix,Obj) {NSLog(@"對(duì)象內(nèi)存地址:%p, 對(duì)象本身:%p, 指向?qū)ο螅?@, --> %@",&Obj,Obj,Obj,prefix);}
  • 創(chuàng)建了兩個(gè)比較簡單的NSObject類,
#import "Obj_A.h"
#import "Obj_B.h"
  • 以下代碼打印以^^^^^為整個(gè)方法的開始與結(jié)束.
具體查看 Obj A dealloc是否有調(diào)用?什么時(shí)候調(diào)用?

對(duì)象之間強(qiáng)引用

__weak和__strong的理解

驗(yàn)證方法一 :

- (void)objProblem1 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj_a = [[Obj_A alloc]init];
    Obj_B *obj_b = [[Obj_B alloc]init];
    obj_a.obj = obj_b;
    obj_b.obj = obj_a;
    NSLog(@"最簡單的例子");
    NSLog(@"這里面對(duì)象A應(yīng)用對(duì)象B,對(duì)象B引用對(duì)象A,兩者之間相互強(qiáng)應(yīng)用.所以會(huì)導(dǎo)致內(nèi)存泄露");
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印結(jié)果

2017-08-16 15:41:57.594 MemoryLeak[21241:695251] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 15:41:57.595 MemoryLeak[21241:695251] 最簡單的例子
2017-08-16 15:41:57.595 MemoryLeak[21241:695251] 這里面對(duì)象A應(yīng)用對(duì)象B,對(duì)象B引用對(duì)象A,兩者之間相互強(qiáng)應(yīng)用.所以會(huì)導(dǎo)致內(nèi)存泄露
2017-08-16 15:41:57.595 MemoryLeak[21241:695251] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

也就是方法結(jié)束之后,dealloc并沒有被執(zhí)行,也就是對(duì)象沒有被釋放

循環(huán)引用
信息定位

驗(yàn)證方法二 :

- (void)objProblem2 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    NSLog(@"__weak會(huì)不會(huì)改善內(nèi)存泄漏問題?");
    Obj_A *obj_a = [[Obj_A alloc]init];
    Obj_B *obj_b = [[Obj_B alloc]init];
    __weak typeof(obj_a) weakObjA = obj_a;

    TLog(@"obj_a", obj_a);
    TLog(@"obj_b", obj_b);
    TLog(@"weakObjA", weakObjA);

    weakObjA.obj = obj_b;
    obj_b.obj = weakObjA;
    
    NSLog(@"weakObjA設(shè)置為nil");

    weakObjA = nil;
    TLog(@"obj_a", obj_a);
    TLog(@"obj_b", obj_b);
    TLog(@"weakObjA", weakObjA);
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");

}

打印結(jié)果

2017-08-16 15:43:54.705 MemoryLeak[21264:696548] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] __weak會(huì)不會(huì)改善內(nèi)存泄漏問題?
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] 對(duì)象內(nèi)存地址:0x7fff5ad8c9b8, 對(duì)象本身:0x60800003f4e0, 指向?qū)ο螅?lt;Obj_A: 0x60800003f4e0>, --> obj_a
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] 對(duì)象內(nèi)存地址:0x7fff5ad8c9b0, 對(duì)象本身:0x60800001f6c0, 指向?qū)ο螅?lt;Obj_B: 0x60800001f6c0>, --> obj_b
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] 對(duì)象內(nèi)存地址:0x7fff5ad8c9a8, 對(duì)象本身:0x60800003f4e0, 指向?qū)ο螅?lt;Obj_A: 0x60800003f4e0>, --> weakObjA
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] weakObjA設(shè)置為nil
2017-08-16 15:43:54.706 MemoryLeak[21264:696548] 對(duì)象內(nèi)存地址:0x7fff5ad8c9b8, 對(duì)象本身:0x60800003f4e0, 指向?qū)ο螅?lt;Obj_A: 0x60800003f4e0>, --> obj_a
2017-08-16 15:43:54.707 MemoryLeak[21264:696548] 對(duì)象內(nèi)存地址:0x7fff5ad8c9b0, 對(duì)象本身:0x60800001f6c0, 指向?qū)ο螅?lt;Obj_B: 0x60800001f6c0>, --> obj_b
2017-08-16 15:43:54.707 MemoryLeak[21264:696548] 對(duì)象內(nèi)存地址:0x7fff5ad8c9a8, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> weakObjA
2017-08-16 15:43:54.707 MemoryLeak[21264:696548] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

這里參考了iOS開發(fā)中本人或同事碰到的內(nèi)存泄漏及解決辦法里面提到的截圖代碼.發(fā)現(xiàn)這樣子使用__weak的話對(duì)內(nèi)存泄露是沒有解決的.也用leaks檢查了好幾遍,同樣是發(fā)現(xiàn)有內(nèi)存泄露.

測試驗(yàn)證

驗(yàn)證方法三 :

- (void)objProblem3 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj = [[Obj_A alloc]init];
    __weak Obj_A *weakObj = obj;

    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);
    
    void(^testBlock)() = ^(){
        TLog(@"weakObj - block", weakObj);
    };
    testBlock();
    NSLog(@"obj設(shè)置為nil");
    obj = nil;
    TLog(@"obj", obj);
    testBlock();
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印結(jié)果

2017-08-16 15:49:35.503 MemoryLeak[21319:699719] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 15:49:35.503 MemoryLeak[21319:699719] 對(duì)象內(nèi)存地址:0x7fff53d6e9b8, 對(duì)象本身:0x6180000293c0, 指向?qū)ο螅?lt;Obj_A: 0x6180000293c0>, --> obj
2017-08-16 15:49:35.503 MemoryLeak[21319:699719] 對(duì)象內(nèi)存地址:0x7fff53d6e9b0, 對(duì)象本身:0x6180000293c0, 指向?qū)ο螅?lt;Obj_A: 0x6180000293c0>, --> weakObj
2017-08-16 15:49:35.503 MemoryLeak[21319:699719] 對(duì)象內(nèi)存地址:0x618000048ae0, 對(duì)象本身:0x6180000293c0, 指向?qū)ο螅?lt;Obj_A: 0x6180000293c0>, --> weakObj - block
2017-08-16 15:49:35.503 MemoryLeak[21319:699719] obj設(shè)置為nil
2017-08-16 15:49:35.504 MemoryLeak[21319:699719] Obj A dealloc
2017-08-16 15:49:35.504 MemoryLeak[21319:699719] 對(duì)象內(nèi)存地址:0x7fff53d6e9b8, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> obj
2017-08-16 15:49:35.504 MemoryLeak[21319:699719] 對(duì)象內(nèi)存地址:0x618000048ae0, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> weakObj - block
2017-08-16 15:49:35.504 MemoryLeak[21319:699719] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

總結(jié) :

  • 當(dāng)obj設(shè)置為nil之后,weakObj在block中失去了引用的對(duì)象,所以不會(huì)導(dǎo)致內(nèi)存泄露.Obj調(diào)用了dealloc在方法結(jié)束之前釋放了對(duì)象.
  • __weak注意使用場景,用于__block

驗(yàn)證方法四 :

__strong關(guān)鍵字

- (void)objProblem4 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj = [[Obj_A alloc]init];
    __weak Obj_A *weakObj = obj;

    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);
    
    void(^testBlock)() = ^(){
        __strong Obj_A *strongObj = weakObj;
        TLog(@"weakObj - block", weakObj);
        TLog(@"strongObj - block", strongObj);
    };
    
    testBlock();
    NSLog(@"obj設(shè)置為nil");
    obj = nil;
    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);

    testBlock();
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印結(jié)果

2017-08-16 15:52:19.971 MemoryLeak[21368:701529] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 15:52:19.971 MemoryLeak[21368:701529] 對(duì)象內(nèi)存地址:0x7fff5e5d99b8, 對(duì)象本身:0x600000031b20, 指向?qū)ο螅?lt;Obj_A: 0x600000031b20>, --> obj
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] 對(duì)象內(nèi)存地址:0x7fff5e5d99b0, 對(duì)象本身:0x600000031b20, 指向?qū)ο螅?lt;Obj_A: 0x600000031b20>, --> weakObj
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] 對(duì)象內(nèi)存地址:0x600000240320, 對(duì)象本身:0x600000031b20, 指向?qū)ο螅?lt;Obj_A: 0x600000031b20>, --> weakObj - block
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] 對(duì)象內(nèi)存地址:0x7fff5e5d9898, 對(duì)象本身:0x600000031b20, 指向?qū)ο螅?lt;Obj_A: 0x600000031b20>, --> strongObj - block
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] obj設(shè)置為nil
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] Obj A dealloc
2017-08-16 15:52:19.972 MemoryLeak[21368:701529] 對(duì)象內(nèi)存地址:0x7fff5e5d99b8, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> obj
2017-08-16 15:52:19.973 MemoryLeak[21368:701529] 對(duì)象內(nèi)存地址:0x7fff5e5d99b0, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> weakObj
2017-08-16 15:52:19.973 MemoryLeak[21368:701529] 對(duì)象內(nèi)存地址:0x600000240320, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> weakObj - block
2017-08-16 15:52:19.973 MemoryLeak[21368:701529] 對(duì)象內(nèi)存地址:0x7fff5e5d9898, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> strongObj - block
2017-08-16 15:52:19.973 MemoryLeak[21368:701529] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

總結(jié):

  • 從上面例子我們看到即使在 block 內(nèi)部用 strong 強(qiáng)引用了外面的 weakObj ,但是一旦 obj 釋放了之后,
  • 內(nèi)部的 strongObj 同樣會(huì)變成 nil,那么這種寫法又有什么意義呢,看驗(yàn)證方法五悲龟?

驗(yàn)證方法五 :

- (void)objProblem5 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj = [[Obj_A alloc]init];
    __weak Obj_A *weakObj = obj;
    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);

    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"start---");
        __strong Obj_A *strongObj = weakObj;
        TLog(@"weakObj - block", weakObj);
        TLog(@"strongObj - block", strongObj);
        sleep(5);
        TLog(@"weakObj - block", weakObj);
        TLog(@"strongObj - block", strongObj);
        NSLog(@"end----");
    });
    sleep(1);
    NSLog(@"*************");
    NSLog(@"After 1s obj設(shè)置為nil");
    obj = nil;
    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);
    NSLog(@"*************");

    sleep(10);
    NSLog(@"After 10s");
    TLog(@"obj", obj);
    TLog(@"weakObj", weakObj);
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印結(jié)果

2017-08-16 15:55:48.772 MemoryLeak[21408:703939] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 15:55:48.772 MemoryLeak[21408:703939] 對(duì)象內(nèi)存地址:0x7fff5bed69b8, 對(duì)象本身:0x610000023c00, 指向?qū)ο螅?lt;Obj_A: 0x610000023c00>, --> obj
2017-08-16 15:55:48.772 MemoryLeak[21408:703939] 對(duì)象內(nèi)存地址:0x7fff5bed69b0, 對(duì)象本身:0x610000023c00, 指向?qū)ο螅?lt;Obj_A: 0x610000023c00>, --> weakObj
2017-08-16 15:55:48.772 MemoryLeak[21408:704010] start---
2017-08-16 15:55:48.772 MemoryLeak[21408:704010] 對(duì)象內(nèi)存地址:0x6000000535e0, 對(duì)象本身:0x610000023c00, 指向?qū)ο螅?lt;Obj_A: 0x610000023c00>, --> weakObj - block
2017-08-16 15:55:48.772 MemoryLeak[21408:704010] 對(duì)象內(nèi)存地址:0x700002cc6d88, 對(duì)象本身:0x610000023c00, 指向?qū)ο螅?lt;Obj_A: 0x610000023c00>, --> strongObj - block
2017-08-16 15:55:49.772 MemoryLeak[21408:703939] *************
2017-08-16 15:55:49.772 MemoryLeak[21408:703939] After 1s obj設(shè)置為nil
2017-08-16 15:55:49.773 MemoryLeak[21408:703939] 對(duì)象內(nèi)存地址:0x7fff5bed69b8, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> obj
2017-08-16 15:55:49.773 MemoryLeak[21408:703939] 對(duì)象內(nèi)存地址:0x7fff5bed69b0, 對(duì)象本身:0x610000023c00, 指向?qū)ο螅?lt;Obj_A: 0x610000023c00>, --> weakObj
2017-08-16 15:55:49.774 MemoryLeak[21408:703939] *************
2017-08-16 15:55:53.777 MemoryLeak[21408:704010] 對(duì)象內(nèi)存地址:0x6000000535e0, 對(duì)象本身:0x610000023c00, 指向?qū)ο螅?lt;Obj_A: 0x610000023c00>, --> weakObj - block
2017-08-16 15:55:53.778 MemoryLeak[21408:704010] 對(duì)象內(nèi)存地址:0x700002cc6d88, 對(duì)象本身:0x610000023c00, 指向?qū)ο螅?lt;Obj_A: 0x610000023c00>, --> strongObj - block
2017-08-16 15:55:53.778 MemoryLeak[21408:704010] end----
2017-08-16 15:55:53.778 MemoryLeak[21408:704010] Obj A dealloc
2017-08-16 15:55:59.774 MemoryLeak[21408:703939] After 10s
2017-08-16 15:55:59.775 MemoryLeak[21408:703939] 對(duì)象內(nèi)存地址:0x7fff5bed69b8, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> obj
2017-08-16 15:55:59.775 MemoryLeak[21408:703939] 對(duì)象內(nèi)存地址:0x7fff5bed69b0, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> weakObj
2017-08-16 15:55:59.775 MemoryLeak[21408:703939] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

總結(jié) :

  • 代碼中使用 sleep 來保證代碼執(zhí)行的先后順序。從結(jié)果中我們可以看到通今,只要 block 部分執(zhí)行了沛厨,即使我們中途釋放了 obj系馆,block 內(nèi)部依然會(huì)繼續(xù)強(qiáng)引用它痴突。
  • 對(duì)比上面代碼搂蜓,也就是說 block 內(nèi)部的 __strong 會(huì)在執(zhí)行期間進(jìn)行強(qiáng)引用操作,保證在 block 內(nèi)部 strongObj 始終是可用的辽装。
  • 這種寫法非常巧妙洛勉,既避免了循環(huán)引用的問題,又可以在 block 內(nèi)部持有該變量如迟。

對(duì)象之間強(qiáng)引用

__block的理解

驗(yàn)證方法一:

- (void)blockProblem1 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj = [[Obj_A alloc]init];
    __block Obj_A *blockObj = obj;

    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);

    NSLog(@"obj設(shè)置為nil");
    obj = nil;
    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);
    
    void(^testBlock)() = ^(){
        NSLog(@"***********開始block***********");
        TLog(@"blockObj - block",blockObj);
        Obj_A *obj2 = [[Obj_A alloc]init];
        TLog(@"obj2",obj2);
        NSLog(@"將blockObj = obj2,只要blockObj不再應(yīng)用obj,那么obj則釋放");
        blockObj = obj2;
        TLog(@"blockObj - block",blockObj);
        NSLog(@"***********結(jié)束block***********");
    };
    
    NSLog(@"設(shè)置block內(nèi)容之后");
    
    TLog(@"blockObj\n--------------------",blockObj);
    
    NSLog(@"運(yùn)行block");
    testBlock();
    TLog(@"blockObj\n--------------------",blockObj);
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印結(jié)果

2017-08-16 16:04:58.457 MemoryLeak[21496:708962] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 16:04:58.458 MemoryLeak[21496:708962] 對(duì)象內(nèi)存地址:0x7fff555dc9b8, 對(duì)象本身:0x600000022c20, 指向?qū)ο螅?lt;Obj_A: 0x600000022c20>, --> obj
2017-08-16 16:04:58.458 MemoryLeak[21496:708962] 對(duì)象內(nèi)存地址:0x7fff555dc9b0, 對(duì)象本身:0x600000022c20, 指向?qū)ο螅?lt;Obj_A: 0x600000022c20>, --> blockObj
----------
2017-08-16 16:04:58.458 MemoryLeak[21496:708962] obj設(shè)置為nil
2017-08-16 16:04:58.458 MemoryLeak[21496:708962] 對(duì)象內(nèi)存地址:0x7fff555dc9b8, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> obj
2017-08-16 16:04:58.458 MemoryLeak[21496:708962] 對(duì)象內(nèi)存地址:0x7fff555dc9b0, 對(duì)象本身:0x600000022c20, 指向?qū)ο螅?lt;Obj_A: 0x600000022c20>, --> blockObj
----------
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 設(shè)置block內(nèi)容之后
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 對(duì)象內(nèi)存地址:0x61000004a408, 對(duì)象本身:0x600000022c20, 指向?qū)ο螅?lt;Obj_A: 0x600000022c20>, --> blockObj
--------------------
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 運(yùn)行block
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] ***********開始block***********
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 對(duì)象內(nèi)存地址:0x61000004a408, 對(duì)象本身:0x600000022c20, 指向?qū)ο螅?lt;Obj_A: 0x600000022c20>, --> blockObj - block
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 對(duì)象內(nèi)存地址:0x7fff555dc8e8, 對(duì)象本身:0x608000022a00, 指向?qū)ο螅?lt;Obj_A: 0x608000022a00>, --> obj2
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] 將blockObj = obj2,只要blockObj不再應(yīng)用obj,那么obj則釋放
2017-08-16 16:04:58.459 MemoryLeak[21496:708962] Obj A dealloc
2017-08-16 16:04:58.460 MemoryLeak[21496:708962] 對(duì)象內(nèi)存地址:0x61000004a408, 對(duì)象本身:0x608000022a00, 指向?qū)ο螅?lt;Obj_A: 0x608000022a00>, --> blockObj - block
2017-08-16 16:04:58.460 MemoryLeak[21496:708962] ***********結(jié)束block***********
2017-08-16 16:04:58.460 MemoryLeak[21496:708962] 對(duì)象內(nèi)存地址:0x61000004a408, 對(duì)象本身:0x608000022a00, 指向?qū)ο螅?lt;Obj_A: 0x608000022a00>, --> blockObj
--------------------
2017-08-16 16:04:58.460 MemoryLeak[21496:708962] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 16:04:58.460 MemoryLeak[21496:708962] Obj A dealloc

總結(jié) :

  • 可以看到在 block 聲明前后 blockObj 的內(nèi)存地址是有所變化的,這涉及到 block 對(duì)外部變量的內(nèi)存管理問題,大家可以看擴(kuò)展閱讀中的幾篇文章殷勘,對(duì)此有較深入的分析此再。
  • 這里可以注意到,雖然沒有執(zhí)行block,但是里面設(shè)置blockObj之后,已經(jīng)對(duì)blockObj進(jìn)行操作了,改變了其內(nèi)存地址.

驗(yàn)證方法二 :

- (void)blockProblem2 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
    Obj_A *obj = [[Obj_A alloc]init];
    __block Obj_A *blockObj = obj;

    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);

    
    NSLog(@"obj設(shè)置為nil");
    obj = nil;
    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);
    NSLog(@"設(shè)置block內(nèi)容");
    
    void(^testBlock)() = ^(){
        TLog(@"blockObj - block",blockObj);
    };
    
    obj = nil;
    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);
    
    NSLog(@"運(yùn)行block");
    testBlock();
    TLog(@"blockObj",blockObj);
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印結(jié)果


總結(jié)

  • 注意Obj A dealloc,是在整個(gè)方法結(jié)束之后.
  • 當(dāng)外部 obj 指向 nil 的時(shí)候,obj 理應(yīng)被釋放玲销,但實(shí)際上 blockObj 依然強(qiáng)引用著 obj输拇,obj 其實(shí)并沒有被真正釋放。因此使用 __block 并不能避免循環(huán)引用的問題贤斜。
  • 但是我們可以通過手動(dòng)釋放 blockObj 的方式來釋放 obj策吠,這就需要我們?cè)?block 內(nèi)部將要退出的時(shí)候手動(dòng)釋放掉 blockObj ,如下這種形式,驗(yàn)證方法三

驗(yàn)證方法三 :

- (void)blockProblem3 {
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");

    Obj_A *obj = [[Obj_A alloc]init];
    __block Obj_A *blockObj = obj;

    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);

    NSLog(@"obj設(shè)置為nil");
    obj = nil;
    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);
    NSLog(@"設(shè)置block內(nèi)容");
    
    void(^testBlock)() = ^(){
        TLog(@"blockObj - block",blockObj);
        NSLog(@"blockObj設(shè)置為nil");
        blockObj = nil;
    };
    NSLog(@"obj設(shè)置為nil");
    obj = nil;
    TLog(@"obj",obj);
    TLog(@"blockObj\n----------",blockObj);
    NSLog(@"運(yùn)行block");
    testBlock();
    TLog(@"blockObj",blockObj);
    NSLog(@"^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^");
}

打印結(jié)果

2017-08-16 16:09:30.042 MemoryLeak[21537:711747] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2017-08-16 16:09:30.042 MemoryLeak[21537:711747] 對(duì)象內(nèi)存地址:0x7fff5e9709b8, 對(duì)象本身:0x600000039560, 指向?qū)ο螅?lt;Obj_A: 0x600000039560>, --> obj
2017-08-16 16:09:30.042 MemoryLeak[21537:711747] 對(duì)象內(nèi)存地址:0x7fff5e9709b0, 對(duì)象本身:0x600000039560, 指向?qū)ο螅?lt;Obj_A: 0x600000039560>, --> blockObj
----------
2017-08-16 16:09:30.042 MemoryLeak[21537:711747] obj設(shè)置為nil
2017-08-16 16:09:30.042 MemoryLeak[21537:711747] 對(duì)象內(nèi)存地址:0x7fff5e9709b8, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> obj
2017-08-16 16:09:30.042 MemoryLeak[21537:711747] 對(duì)象內(nèi)存地址:0x7fff5e9709b0, 對(duì)象本身:0x600000039560, 指向?qū)ο螅?lt;Obj_A: 0x600000039560>, --> blockObj
----------
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] 設(shè)置block內(nèi)容
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] obj設(shè)置為nil
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] 對(duì)象內(nèi)存地址:0x7fff5e9709b8, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> obj
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] 對(duì)象內(nèi)存地址:0x608000050ee8, 對(duì)象本身:0x600000039560, 指向?qū)ο螅?lt;Obj_A: 0x600000039560>, --> blockObj
----------
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] 運(yùn)行block
2017-08-16 16:09:30.043 MemoryLeak[21537:711747] 對(duì)象內(nèi)存地址:0x608000050ee8, 對(duì)象本身:0x600000039560, 指向?qū)ο螅?lt;Obj_A: 0x600000039560>, --> blockObj - block
2017-08-16 16:09:30.044 MemoryLeak[21537:711747] blockObj設(shè)置為nil
2017-08-16 16:09:30.044 MemoryLeak[21537:711747] Obj A dealloc
2017-08-16 16:09:30.044 MemoryLeak[21537:711747] 對(duì)象內(nèi)存地址:0x608000050ee8, 對(duì)象本身:0x0, 指向?qū)ο螅?null), --> blockObj
2017-08-16 16:09:30.044 MemoryLeak[21537:711747] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

總結(jié)

  • 這里也就是提前手動(dòng)釋放block引用的對(duì)象,這種形式既能保證在 block 內(nèi)部能夠訪問到 obj瘩绒,又可以避免循環(huán)引用的問題猴抹,但是這種方法也不是完美的,其存在下面幾個(gè)問題
      1. 必須記住在 block 底部釋放掉 block 變量锁荔,這其實(shí)跟 MRC 的形式有些類似了蟀给,不太適合 ARC
      1. 當(dāng)在 block 外部修改了 blockObj 時(shí),block 內(nèi)部的值也會(huì)改變阳堕,反之在 block 內(nèi)部修改 blockObj 在外部再使用時(shí)值也會(huì)改變跋理。
      1. 這就需要在寫代碼時(shí)注意這個(gè)特性可能會(huì)帶來的一些隱患 ,__block 其實(shí)提升了變量的作用域,在 block 內(nèi)外訪問的都是同一個(gè) blockObj 可能會(huì)造成一些隱患

關(guān)于__weak和__strong的總結(jié)

總結(jié)

  • __weak 本身是可以避免循環(huán)引用的問題的恬总,但是其會(huì)導(dǎo)致外部對(duì)象釋放了之后前普,block 內(nèi)部也訪問不到這個(gè)對(duì)象的問題,我們可以通過在 block 內(nèi)部聲明一個(gè) __strong 的變量來指向 weakObj壹堰,使外部對(duì)象既能在 block 內(nèi)部保持住拭卿,又能避免循環(huán)引用的問題。

  • __block 本身無法避免循環(huán)引用的問題缀旁,但是我們可以通過在 block 內(nèi)部手動(dòng)把 blockObj 賦值為 nil 的方式來避免循環(huán)引用的問題记劈。另外一點(diǎn)就是 __block 修飾的變量在 block 內(nèi)外都是唯一的,要注意這個(gè)特性可能帶來的隱患并巍。


參考博文 :
block教程系列
__weak與__block區(qū)別

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末目木,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子懊渡,更是在濱河造成了極大的恐慌刽射,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剃执,死亡現(xiàn)場離奇詭異誓禁,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)肾档,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門摹恰,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辫继,“玉大人,你說我怎么就攤上這事俗慈」每恚” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵闺阱,是天一觀的道長炮车。 經(jīng)常有香客問我,道長酣溃,這世上最難降的妖魔是什么瘦穆? 我笑而不...
    開封第一講書人閱讀 55,259評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮赊豌,結(jié)果婚禮上扛或,老公的妹妹穿的比我還像新娘。我一直安慰自己亿絮,他們只是感情好告喊,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著派昧,像睡著了一般黔姜。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蒂萎,一...
    開封第一講書人閱讀 49,036評(píng)論 1 285
  • 那天秆吵,我揣著相機(jī)與錄音,去河邊找鬼五慈。 笑死纳寂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的泻拦。 我是一名探鬼主播毙芜,決...
    沈念sama閱讀 38,349評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼争拐!你這毒婦竟也來了腋粥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,979評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤架曹,失蹤者是張志新(化名)和其女友劉穎隘冲,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绑雄,經(jīng)...
    沈念sama閱讀 43,469評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡展辞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了万牺。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罗珍。...
    茶點(diǎn)故事閱讀 38,059評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洽腺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出靡砌,到底是詐尸還是另有隱情已脓,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評(píng)論 4 323
  • 正文 年R本政府宣布通殃,位于F島的核電站,受9級(jí)特大地震影響厕宗,放射性物質(zhì)發(fā)生泄漏画舌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評(píng)論 3 307
  • 文/蒙蒙 一已慢、第九天 我趴在偏房一處隱蔽的房頂上張望曲聂。 院中可真熱鬧,春花似錦佑惠、人聲如沸朋腋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽旭咽。三九已至,卻和暖如春赌厅,著一層夾襖步出監(jiān)牢的瞬間穷绵,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評(píng)論 1 262
  • 我被黑心中介騙來泰國打工特愿, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留仲墨,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,501評(píng)論 2 354
  • 正文 我出身青樓揍障,卻偏偏與公主長得像目养,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子毒嫡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評(píng)論 2 345

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