iOS弱引用
创始人
2024-11-05 11:37:11

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

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

解决方案一:

重写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方法SEL     SEL 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.

相关内容

热门资讯

裸辞做“一人公司”,我后悔了 去年这个时候,一位以色列程序员正在东南亚旅行。他顺手把一个在脑子里转了很久的想法做成了产品,一个让任...
南京建成国内首个Pre-6G试... 4月21日,2026全球6G技术与产业生态大会在南京开幕。全息互动技术展台前,一名远在北京的工作人员...
超梵求职受邀参加“2025抖音... 超梵求职受邀参加“2025抖音巨量引擎成人教育行业生态大会”,探讨分享优质内容传播,服务万千学员。 ...
摩托罗拉Razr 2026(R... IT之家 4 月 22 日消息,摩托罗拉宣布新一代 Razr 折叠手机将于 4 月 29 日在美国发...
库克卸任,特纳斯领航:苹果新纪... 苹果首席执行官蒂姆·库克将卸任,硬件工程主管约翰·特纳斯将接任,苹果公司今天宣布此事。 库克将在夏季...