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

iOS弱引用

背景:在面试过程中被问到如果两个对象已经发生循环引用了,该如何将他们剪断,在运行态的时候。

由于这个场景比较抽象,我理解面试官是希望我通过运行时的方法和方式来解决循环引用。

解决方案一:

重写setter用关联对象来实现weak引用。由于objc_setAssociatedObject中的策略不支持weak修饰对象属性。如果我们可以借助中间类或者block持有弱引用对象来实现。

- (void)setMyObject:(id)myObject
{id __weak weakObject = myObject;id (^block)(void) = ^ {return weakObject;};objc_setAssociatedObject(self, @selector(myObject), block, OBJC_ASSOCIATION_COPY_NONATOMIC);
}- (id)myObject
{id (^block)(void) = objc_getAssociatedObject(self, _cmd);return block();
}

解决方案二:

还是重写setter通过关联对象实现弱引用,但是弱引用的实现不是通过中间对象的方式,而是通过runtime运行时重写value对象的子类的delloc方法,在这个方法中将关联对象的value设置成ni;

void weak_setAssociatedObject(id _Nonnull object,const void * _Nonnull key,id _Nullable value) {//派生一个子类,类名为WeakObjWrapper+value对应的类名const char *clsName = [[NSString stringWithFormat:@"WeakObjWrapper%@", [value class]] UTF8String];//获取派生的子类Class childCls = objc_getClass(clsName);//如果子类不存在,利用runtime动态的创建一个子类if (!childCls) {childCls = objc_allocateClassPair([value class], clsName, 0);objc_registerClassPair(childCls);}//注册dealloc方法SELSEL sel = sel_registerName("dealloc");//获取dealloc对应的类型编码const char *deallocEncoding = method_getTypeEncoding(class_getInstanceMethod([value class], sel));// 注意:内部持有value此处需要弱引用处理一下__weak typeof(value) weakValue = value;// 创建一个指向在调用dealloc方法时调用指定block的函数指针IMP deallocImp = imp_implementationWithBlock(^(id _childCls) {//在子类的dealloc方法中将value设置为nil,避免崩溃objc_setAssociatedObject(object, key, nil, OBJC_ASSOCIATION_ASSIGN);//派生的子类的dealloc方法会被调用,父类的不再被调用,故在此处调用一下父类的((void (*)(id, SEL))(void *)objc_msgSend)(weakValue, sel);});//给子类添加dealloc方法class_addMethod(childCls, sel, deallocImp, deallocEncoding);//将value对应的isa指向子类object_setClass(value, childCls);//设置关联对象objc_setAssociatedObject(object, key, value, OBJC_ASSOCIATION_ASSIGN);
}- (id)anthorObj
{return objc_getAssociatedObject(self, _cmd);
}- (void)setAnthorObj:(id)anthorObj
{weak_setAssociatedObject(self, @selector(anthorObj), anthorObj);
}

测试代码如下:

Engine * a = [[Engine alloc] init];{Tire * b = [[Tire alloc] init];Tire * c = [[Tire alloc] init];a.myObject = b;a.anthorObj = c;NSLog(@"myObject%@", a.myObject);NSLog(@"anthorObject%@", a.anthorObj);}NSLog(@"myObject outer%@", a.myObject);NSLog(@"anthorObject outer%@", a.anthorObj);

可以看到过了b、c对象出了作用域后,a.myObject以及a.anthorObject被改成nil.

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【Apache Doris】周FAQ集锦:第 18 期
  • 正则表达式测试工具
  • 【环境】Rocky8使用gvm配置Go多版本管理的微服务开发环境(go-zero)
  • [Git][分支设计规范]详细讲解
  • VSCode在windows系统下的配置简单版
  • ArcGIS for js 缓冲(vue项目)
  • 代码”byte a = 0Xa1“为什么会报编译错误?
  • python游戏开发之五子棋游戏制作
  • Fast-DDS的依赖 foonathan_memory_vendor编译
  • ZICO2: 1【附代码】(权限提升)
  • 智算新风向丨趋动科技获中国信通院泰尔实验室首张智算资源池化能力泰尔测评证书
  • U2net论文复现-简单解读-以及奇奇怪怪的改进-测试roc以及pr
  • 机器学习用Python 还是 R语言?
  • Unknown input format pdf Pandoc can convert to PDF, but not from PDF.解决方案
  • Webkit与Web Push API:提升用户体验的推送技术
  • 《Javascript高级程序设计 (第三版)》第五章 引用类型
  • 【刷算法】从上往下打印二叉树
  • ES6核心特性
  • extjs4学习之配置
  • Node.js 新计划:使用 V8 snapshot 将启动速度提升 8 倍
  • 从PHP迁移至Golang - 基础篇
  • 动态规划入门(以爬楼梯为例)
  • 番外篇1:在Windows环境下安装JDK
  • 融云开发漫谈:你是否了解Go语言并发编程的第一要义?
  • 数据仓库的几种建模方法
  • 通过npm或yarn自动生成vue组件
  • 微信小程序开发问题汇总
  • #include到底该写在哪
  • $refs 、$nextTic、动态组件、name的使用
  • (2)STL算法之元素计数
  • (20050108)又读《平凡的世界》
  • (3)选择元素——(14)接触DOM元素(Accessing DOM elements)
  • (zt)基于Facebook和Flash平台的应用架构解析
  • (十五)Flask覆写wsgi_app函数实现自定义中间件
  • (转)shell中括号的特殊用法 linux if多条件判断
  • ****** 二 ******、软设笔记【数据结构】-KMP算法、树、二叉树
  • ***详解账号泄露:全球约1亿用户已泄露
  • .[hudsonL@cock.li].mkp勒索病毒数据怎么处理|数据解密恢复
  • .Net 4.0并行库实用性演练
  • .NET MAUI学习笔记——2.构建第一个程序_初级篇
  • .net 生成二级域名
  • /proc/vmstat 详解
  • [ Algorithm ] N次方算法 N Square 动态规划解决
  • [C#] 基于 yield 语句的迭代器逻辑懒执行
  • [C++]类和对象【上篇】
  • [C++]命名空间等——喵喵要吃C嘎嘎
  • [CERC2017]Cumulative Code
  • [Doris]阿里云搭建Doris,测试环境1FE 1BE
  • [EFI]英特尔 冥王峡谷 NUC8i7HVK 电脑 Hackintosh 黑苹果efi引导文件
  • [FlareOn5]Ultimate Minesweeper
  • [IE9] IE9 beta版下载链接
  • [leetcode] Longest Palindromic Substring
  • [linux]linux命令学习-netstat
  • [Oh My C++ Diary]类继承和类组合(内嵌类)初始化的不同
  • [PTA]数组循环右移