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

前言

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);
}

该函数单纯的调用了 storeWeak

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值