当前位置: 首页 > news >正文

OC对象 - Block解决循环引用

文章目录

  • OC对象 - Block解决循环引用
    • 前言
    • 1. 循环引用示例
      • 1.1 分析
    • 2. 解决思路
    • 3. ARC下
      • 3.1 __weak
      • 3.2 __unsafe_unretained
      • 3.3 __block
    • 4. MRC下
      • 4.1 __unsafe_unretain....
      • 4.1 __block
    • 5. 总结
      • 5.1 ARC下
      • 5.2 MRC下

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

相关文章:

  • AWTK 开源串口屏开发(15) - 通过 MODBUS 访问远程设备数据
  • 【微服务】认识Dubbo+基本环境搭建
  • 【QT学习】1.qt初识,创建qt工程,使用按钮,第一个交互按钮
  • Kafka开机自启脚本
  • 数据结构:单调栈和单调队列
  • 【pytest】测试数据存储在 Excel 或 TXT 文件中,如何参数化
  • MongoDB聚合运算符:$linearFill
  • 深入理解数据结构第一弹——二叉树(1)——堆
  • 【动态规划】1223. 掷骰子模拟
  • Linux 环境安装 Elasticsearch 8.X
  • 【医学嵌入模型】中文医疗文本处理大模型 PCL-MedBERT
  • Redis Scan指令解析与使用示例
  • 再见 mysql_upgrade
  • CentOS 7 安装python 3.7 需要必要的依赖。
  • 《Effective C++》《构造/析构/赋值运算——7、为多态基类声明virtual析构函数》
  • 收藏网友的 源程序下载网
  • [分享]iOS开发 - 实现UITableView Plain SectionView和table不停留一起滑动
  • 【Under-the-hood-ReactJS-Part0】React源码解读
  • 【编码】-360实习笔试编程题(二)-2016.03.29
  • 【从零开始安装kubernetes-1.7.3】2.flannel、docker以及Harbor的配置以及作用
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • create-react-app做的留言板
  • echarts花样作死的坑
  • eclipse的离线汉化
  • ES6之路之模块详解
  • export和import的用法总结
  • Java的Interrupt与线程中断
  • java多线程
  • Laravel5.4 Queues队列学习
  • Linux CTF 逆向入门
  • MaxCompute访问TableStore(OTS) 数据
  • scala基础语法(二)
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • Vue2.0 实现互斥
  • 基于组件的设计工作流与界面抽象
  • 前端面试题总结
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 突破自己的技术思维
  • 一些关于Rust在2019年的思考
  • 在Unity中实现一个简单的消息管理器
  • “十年磨一剑”--有赞的HBase平台实践和应用之路 ...
  • puppet连载22:define用法
  • ​ 全球云科技基础设施:亚马逊云科技的海外服务器网络如何演进
  • ​MPV,汽车产品里一个特殊品类的进化过程
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • (09)Hive——CTE 公共表达式
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (续)使用Django搭建一个完整的项目(Centos7+Nginx)
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • *Django中的Ajax 纯js的书写样式1
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .net2005怎么读string形的xml,不是xml文件。
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth