iOS进阶

06.6-OC中block循环引用问题

2020-06-14  本文已影响0人  光强_上海

block的循环引用

我们新建一个工程,然后新建Person类,在main函数中编写如下测试代码:

Person

typedef void(^MyBlock)(void);

@interface Person : NSObject

@property (nonatomic, assign) int age;

@property (nonatomic, copy) MyBlock block;
@end


@implementation Person

- (void)dealloc {
    NSLog(@"%s", __func__);
}
@end

main函数

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        Person *person = [[Person alloc] init];
        person.age = 10;
        
        person.block = ^{
            NSLog(@"%d",person.age);
        };
        
        person.block();
    }
    
    NSLog(@"222");
    return 0;
}

运行程序发现person对象没有正常释放,产生循环引用,示例图如下:

image

那么如何解决block的循环引用问题尼,我们可以使用下面两个关键字:

我们先来使用__weak解决循环引用,代码如下:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        
        Person *person = [[Person alloc] init];
        person.age = 10;
        
        __weak typeof(Person) *weakPerson = person;

        person.block = ^{
            // 在block内部再使用__strong,这样防止在block内部使用`person`对象时,`person`对象提前销毁
            __strong typeof(Person) *strongPreson = weakPerson;
            
            NSLog(@"%d",strongPreson.age);
        };
        
        person.block();
    }
    
    NSLog(@"222");
    return 0;
}

引用关系如图所示:

image

我们先来使用__unsafe_unretained解决循环引用,代码如下:

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        // insert code here...
        
        Person *person = [[Person alloc] init];
        person.age = 10;
        
        __unsafe_unretained typeof(Person) *weakPerson = person;

        person.block = ^{
            // 在block内部再使用__strong,这样防止在block内部使用`person`对象时,`person`对象提前销毁
            __strong typeof(Person) *strongPreson = weakPerson;
            
            NSLog(@"%d",strongPreson.age);
        };
        
        person.block();
    }
    
    NSLog(@"222");
    return 0;
}

引用关系如图所示:

image

既然__weak__unsafe_unretained都能解决循环引用,那它们有什么不同?

__weak:当指针指向的对象销毁时,使用__weak修饰的指针的内存地址值会自动赋值为nil

__unsafe_unretained:当指针指向的对象销毁时,使用__unsafe_unretained修饰的指针的内存地址值不变

使用__unsafe_unretained修饰,当指针指向的对象销毁时,指针的内存地址不变,如果还使用这个指针来发送消息就容易导致野指针错误,所以在ARC环境下,我们还是优先选择使用__weak来解决block循环引用问题

解决block循环引用总结如图:

image

讲解示例代码Demo地址:https://github.com/guangqiang-liu/06.6-BlockDemo6

更多文章

上一篇 下一篇

猜你喜欢

热点阅读