iOS弱引用

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

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

解决方案一:

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

objectivec 复制代码
- (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;

objectivec 复制代码
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);
}

测试代码如下:

objectivec 复制代码
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.

相关推荐
非专业程序员Ping5 小时前
一文读懂字体文件
ios·swift·assembly·font
wahkim9 小时前
移动端开发工具集锦
flutter·ios·android studio·swift
2501_9160074710 小时前
提升 iOS 26 系统流畅度的实战指南,多工具组合监控
android·macos·ios·小程序·uni-app·cocoa·iphone
hellojackjiang201112 小时前
全面适配iOS 26液态玻璃,基于开源IM即时通讯框架MobileIMSDK:RainbowChat-iOS端v10.2发布
ios·网络编程·即时通讯·im开发·rainbowchat
非专业程序员Ping15 小时前
一文读懂字符、字形、字体
ios·swift·font
2501_9159214316 小时前
iOS 应用代上架流程,多工具组合与使用 开心上架 跨平台自动化上传指南
android·ios·小程序·uni-app·自动化·cocoa·iphone
日日行不惧千万里16 小时前
2025最新仿默往 IM 即时通讯系统源码(PC + Web + iOS + Android)完整版发布!
android·ios
歪歪10016 小时前
React Native开发Android&IOS流程完整指南
android·开发语言·前端·react native·ios·前端框架
阿里超级工程师18 小时前
ios云打包证书申请不需要苹果电脑也是可以的
ios·证书·云打包
2501_9159184120 小时前
iOS 混淆与 IPA 加固一页式行动手册(多工具组合实战 源码成品运维闭环)
android·运维·ios·小程序·uni-app·iphone·webview