OC对象 - Block解决循环引用

OC对象 - Block解决循环引用

前言

本章将会通过一个循环引用案例,分析其原因,以及在ARCMRC下的解决方案

1. 循环引用示例

ZSXperson

@interface ZSXPerson : NSObject

@property (nonatomic, assign) int age;
@property (nonatomic, copy) void(^block)(void);

@end


@implementation ZSXPerson

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

@end

main.m 中初始化ZSXperson对象person,创建personblock,并在block里面访问person.age

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        person.block = ^ {
            NSLog(@"person.age is %d", person.age);
        };
        NSLog(@"---------------");
    }
    return 0;
}

运行:

person不会销毁

1.1 分析

  • 初始化ZSXperson对象person,然后将block赋值给personblock,此时person是强引用block
  • block中,访问了person.age,因为访问了局部变量,所以block捕获了person
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc -fobjc-arc -fobjc-runtime=ios-13.0.0 main.m -o main-arm64.cpp

  • 此时blockperson的关系,是相互持有的关系

2. 解决思路

之所以叫循环引用,其实就是相互之间的引用关系形成了环

解决方式就是,断开某个引用关系,打破这个环

3. ARC下

3.1 __weak

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        __weak typeof(person) weakPerson = person;
        person.block = ^ {
            NSLog(@"person.age is %d", weakPerson.age);
        };
        NSLog(@"---------------");
    }
    return 0;
}

person正常销毁的

3.2 __unsafe_unretained

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        __unsafe_unretained typeof(person) uuPerson = person;
        person.block = ^ {
            NSLog(@"person.age is %d", uuPerson.age);
        };
        NSLog(@"---------------");
    }
    return 0;
}

使用__unsafe_unretained也可以正常释放

__unsafe_unretained从命名看,unsafe代表不安全,unretained表示不会产生引用。不安全则表现在,当引用的对象销毁时,他不会把指针设置为nil,因此容易有坏指针异常

3.3 __block

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        person.age = 10;
        __block typeof(person) strongPerson = person;
        person.block = ^ {
            NSLog(@"person.age is %d", strongPerson.age);
            strongPerson = nil;
        };
        person.block();
        NSLog(@"---------------");
    }
    return 0;
}


使用__block正常销毁

需要注意的是,使用__block必须调用block。因为使用__block修饰后,在block里面需要置空,如果没有调用block,就没有置空操作,它依然是循环引用状态无法销毁

未调用block:

调用block后:

4. MRC下

MRC不支持__weak
改为MRC

4.1 __unsafe_unretain…

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        person.age = 10;
        __unsafe_unretained typeof(person) weakPerson = person;
        person.block = [^ {
            NSLog(@"person.age is %d", weakPerson.age);
        } copy];
        NSLog(@"---------------");
        [person release];
    }
    return 0;
}

正常销毁

4.1 __block

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
        ZSXPerson *person = [[ZSXPerson alloc] init];
        person.age = 10;
        __block typeof(person) weakPerson = person;
        person.block = [^ {
            NSLog(@"person.age is %d", weakPerson.age);
        } copy];
        NSLog(@"---------------");
        [person release];
    }
    return 0;
}

正常销毁

MRC下,block 里面无需将weakPerson设置为nil,也能正常释放。这是因为,MRC__block不会对person产生强引用(被__block修饰的对象类型,ARC时会retain,MRC时不会retain)

相当于这根线不生效,因此没有形成循环引用

5. 总结

5.1 ARC下

通常使用__weak来解决循环引用。使用__weak修饰的对象销毁后,指针会自动设置为nil__unsafe_unretained__block虽然也可以解决环引用问题,但是__unsafe_unretained在修饰的对象销毁后,指针不会自动设置为nil,因此如果还去使用这个对象就会出现异常。__block需要保证 block 有被调用,否则还是会循环引用。

5.2 MRC下

使用__unsafe_unretained或者__block

@oubijiexi

相关推荐

  1. SpringBoot 循环引用解决办法

    2024-03-26 15:08:02       32 阅读
  2. 大白话解析LevelDB: Block Iterator

    2024-03-26 15:08:02       44 阅读
  3. 通过接口引用对象

    2024-03-26 15:08:02       54 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-26 15:08:02       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-26 15:08:02       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-26 15:08:02       82 阅读
  4. Python语言-面向对象

    2024-03-26 15:08:02       91 阅读

热门阅读

  1. 设计模式之观察者模式

    2024-03-26 15:08:02       40 阅读
  2. 服务器相关问题以及见解

    2024-03-26 15:08:02       27 阅读
  3. Ubuntu 安装教程

    2024-03-26 15:08:02       39 阅读
  4. 【C/C++】多项式求和

    2024-03-26 15:08:02       47 阅读
  5. 【学习心得】人工智能概念拾遗

    2024-03-26 15:08:02       42 阅读
  6. Modbus TCP协议介绍(ModbusTCP)

    2024-03-26 15:08:02       31 阅读
  7. Elasticsearch 基础之映射(mappping)

    2024-03-26 15:08:02       44 阅读
  8. 网络小基础

    2024-03-26 15:08:02       38 阅读
  9. Docker in Docker原理与实战

    2024-03-26 15:08:02       43 阅读