美文网首页
iOS底层 -- Blcok本质之循环引用

iOS底层 -- Blcok本质之循环引用

作者: happy神悦 | 来源:发表于2020-09-11 10:05 被阅读0次

    一、产生循环引用的原因

    //Person.h
    typedef void(^Block)(void);
    
    @interface Person : NSObject
    
    @property (nonatomic, copy) Block block;
    
    @end
    
    //main.m
    int main(int argc, char * argv[]) {
        @autoreleasepool {
            Person *person = [[Person alloc] init];
            person.block = ^{
                NSLog(@"%@", person);
            };
        }
        return 0;
    }
    
    //block底层结构
    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      Person *__strong weakPerson; //强引用
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, int flags=0) : person(_person) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    

    由图可知,person对象强引用block,block强引用person对象,形成循环引用,就这样person对象的内存就一直不能被释放。

    二、解决循环引用问题 - ARC

    1.用__weak、__unsafe_unretained解决

    Person *person = [[Person alloc] init];
    __weak typeof(person) weakperson = person;
    person.mblock = ^{
        NSLog(@"%@", weakperson);
    }
    
    Person *person = [[Person alloc] init];
    __unsafe_unretained typeof(person) weakperson = person;
    person.mblock = ^{
        NSLog(@"%@", weakperson);
    }
    
    //block底层结构
    struct __main_block_impl_0 {
      struct __block_impl impl;
      struct __main_block_desc_0* Desc;
      Person *__weak weakPerson; //弱引用
      __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, Person *_person, int flags=0) : person(_person) {
        impl.isa = &_NSConcreteStackBlock;
        impl.Flags = flags;
        impl.FuncPtr = fp;
        Desc = desc;
      }
    };
    

    使用__weak或者__unsafe_unretained创建weakPerson对象,这样block结构体内的成员变量person指针就是一个弱指针,就能使黑色箭头变成虚线。

    2.用__block解决(必须要调用block)

    __blcok id weakSelf = self;
    self.blcok = ^{
        NSLog(@"%@", weakSelf);
        weakSelf = nil;
    };
    self.blcok();
    

    因为block执行了,将auto类型的自动变量置为nil,__block变量拥有对象那条线消失了,就打破了循环引用。

    相关文章

      网友评论

          本文标题:iOS底层 -- Blcok本质之循环引用

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