美文网首页iOS基础
Block 解决循环引用(ARC、MRC)

Block 解决循环引用(ARC、MRC)

作者: 再好一点点 | 来源:发表于2021-11-03 10:08 被阅读0次

    关于block的上一篇文章Block内部实现
    __weak、__strong、__block修饰Block的内部实现原理

    一. 先看一下被__block修饰的对象类型数据结构

    __block Person *person = [[Person alloc] init];
    Person对象被包装成了以下这种数据结构:

    struct __Block_byref_person_0 {
      void *__isa;
    __Block_byref_person_0 *__forwarding;
     int __flags;
     int __size;
     void (*__Block_byref_id_object_copy)(void*, void*);
     void (*__Block_byref_id_object_dispose)(void*);
     MJPerson *__strong person;
    };
    

    可看到含有这两个函数__Block_byref_id_object_copy__Block_byref_id_object_dispose,是block用来处理block对这个对象的持有情况的。__block修饰基本数据类型是不会有这两个函数的。

    1. 当__block变量被copy到堆时
      a) 会调用__block变量内部的copy函数
      b) copy函数内部会调用_Block_object_assign函数
      c) _Block_object_assign函数会根据所指向对象的修饰符(__strong、__weak、__unsafe_unretained)做出相应的操作,形成强引用(retain)或者弱引用(注意:这里仅限于ARC时会retain,MRC时不会retain)

    了解了这个下面会用得到。

    二. 在ARC下解决循环引用可以使用以下三种方法。

    1. 使用__weak

    推荐使用。在weak修饰的对象内存被释放的时候,weak修饰的对象会自动置为nil。

     __weak typeof(self) weakSelf = self;
        self.block = ^{
            NSLog(@"%p", weakSelf);
        };
    
    2. 使用__unsafe_unretained

    不推荐使用。如果被修饰对象内存释放以后访问该对象会报野指针错误。

     __unsafe_unretained typeof(self) weakSelf = self;
        self.block = ^{
            NSLog(@"%p", weakSelf);
        };
    

    以上两种循环引用示意图如下:


    download.png
    3. 使用__block解决(必须要调用block)

    不推荐使用。如果该block没有被调用,存在内存泄漏风险。

     __block id weakSelf = self;
        self.block = ^{
            NSLog(@"%p", weakSelf);
            weakSelf = nil;
        };
        self.block();
    

    第三种循环引用示意图如下:


    download-1.png

    三. 在MRC下解决循环引用可以使用以下两种方法。

    1. 使用__unsafe_unretained
     __unsafe_unretained typeof(self) weakSelf = self;
        self.block = ^{
            NSLog(@"%p", weakSelf);
        };
    
    2. 使用__block

    这种情况能够解决循环引用是因为文章顶部解释了__block修饰的对象类型数据结构。在MRC下_Block_object_assign不会对持有对象执行retain操作。所以默认就是弱引用。

     __block id weakSelf = self;
        self.block = ^{
            NSLog(@"%p", weakSelf);
        };
    

    四. block在修改NSMutableArray时,需不需要添加__block?

    如图所示:

    NSMutableArray *array = [NSMutableArray array];
            void (^block)(void) = ^{
                [array addObject:@10];
            };
    

    这种情况是不会报错的,因为没有修改array的指向,只是使用了array而已。所以不需要添加__block。

    相关文章

      网友评论

        本文标题:Block 解决循环引用(ARC、MRC)

        本文链接:https://www.haomeiwen.com/subject/kdpqzltx.html