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

2020-09-11  本文已影响0人  happy神悦

一、产生循环引用的原因

//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变量拥有对象那条线消失了,就打破了循环引用。

上一篇下一篇

猜你喜欢

热点阅读