ObjC Runtime 中 Weak 属性的实现 (上)

本文探讨了Objective-C Runtime中弱引用属性(weak)的实现机制,涉及弱引用对象在释放后自动置为nil的过程。通过分析源码,揭示了弱引用表(WeakRefereneceTable)在对象生命周期中的作用,以及如何在对象释放时更新弱引用的值。文章深入浅出地解析了相关函数,如assign_weak、loadWeak、storeWeak等,并介绍了自旋锁在弱引用表中的应用。
摘要由CSDN通过智能技术生成

前言

OC 中的 weak 属性是怎么实现的,为什么在对象释放后会自动变成 nil?本文对这个问题进行了一点探讨。

环境

mac OS Sierra 10.12.4
objc709

参考答案

搜索后发现runtime 如何实现 weak 属性给出了一个参考答案。

runtime 对注册的类, 会进行布局,对于 weak 对象会放入一个 hash 表中。 用 weak 指向的对象内存地址作为 key,当此对象的引用计数为 0 的时候会 dealloc,假如 weak 指向的对象内存地址是 a ,那么就会以 a 为键, 在这个 weak 表中搜索,找到所有以 a 为键的 weak 对象,从而设置为 nil

测试

代码

#import <Foundation/Foundation.h>

@interface WeakProperty : NSObject

@property (nonatomic,weak) NSObject *obj;


@end

@implementation WeakProperty

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

@end


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        WeakProperty *property = [[WeakProperty alloc] init];
        NSObject *obj = [[NSObject alloc] init];
        property.obj = obj;     
        NSLog(@"%@",property.obj);   

        // 会触发函数 ``id objc_initWeak(id *location, id newObj)``       
        // NSObject *obj = [[NSObject alloc] init];
        // __weak NSObject *obj2 = obj;
        // 会触发函数 ``void objc_copyWeak(id *dst, id *src)``
        // __weak NSObject *obj3 = obj2;
    }
    return 0;
}

结果

对象的 weak 属性调用 setter

  • 调用 id objc_storeWeak(id *location, id newObj)
  • 调用 static id storeWeak(id *location, objc_object *newObj)

使用 NSLog 输出 property.obj 属性时

  • 调用 id objc_loadWeakRetained(id *location)

dealloc 释放对象时

  • 调用 void objc_destroyWeak(id *location)

相关函数

查看 NSObject.mm 源码发现

  • id objc_storeWeak(id *location, id newObj)
  • id objc_storeWeakOrNil(id *location, id newObj)
  • id objc_initWeak(id *location, id newObj)
  • id objc_initWeakOrNil(id *location, id newObj)
  • void objc_destroyWeak(id *location)

都调用了 static id storeWeak(id *location, objc_object *newObj) , objc_xxxWeakOrNil 多了一点额外的处理,但并不影响整体的理解。而 void objc_destroyWeak(id *location) 在调用 static id storeWeak(id *location, objc_object *newObj)newObj 参数传递的是 nil 这一点与上面提到的参考答案中关于 dealloc 释放对象时,将哈希表中指定的键对应的值设置为 nil 是符合的。

小结

  • storeWeak 函数用于为 weak 属性赋值 (包括销毁)
  • objc_loadWeakRetained 函数用于获取 weak 属性

观察 & 分析

对于函数 storeWeak 主要分析两种情况下的调用

  1. 赋值,即 id objc_storeWeak(id *location, id newObj)
  2. 销毁,即 void objc_destroyWeak(id *location)

而对于 weak 属性的获取主要分析

  1. 函数 id objc_loadWeakRetained(id *location)

观察: id objc_storeWeak(id *location, id newObj)

/** 
 * This function stores a new value into a __weak variable. It would
 * be used anywhere a __weak variable is the target of an assignment.
 * 
 * @param location The address of the weak pointer itself
 * @param newObj The new object this weak ptr should now point to
 * 
 * @return \e newObj
 */
id
objc_storeWeak(id *location, id newObj)
{
    return storeWeak<DoHaveOld, DoHaveNew, DoCrashIfDeallocating>
        (location, (objc_object *)newObj);
}

该函数单纯的调

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值