iOS weak 底层实现原理(一):DisguisedPtr

原文:https://juejin.im/post/6865468675940417550

DisguisedPtr

为了全面透彻的理解 weak 关键字,现在从最底层的数据结构开始挖掘,力求构建一个完整的认知体系。

定义位于: Project Headers/objc-private.h Line 904

指针伪装模版类 Disguised,与此对应的概念是指针伪装

DisguisedPtr 通过运算使指针隐藏于系统工具(如 leaks 工具),同时保持指针的能力,其作用是通过计算把保存的 T 的指针隐藏起来,实现指针到整数的映射。

根据 Disguised 这个英文单词我们或许能猜出一部分信息,PtrPointer (指针)的缩写,硬翻译的话可以理解为:掩藏指针封装指针,看它的定义再直白一点的话,大概就是指针本身的地址值与 unsigned long 来回相互转化。

Disguised /dɪs'ɡaɪz/
vt. 假装;掩饰;隐瞒
n. 伪装;假装;用作伪装的东西
复制代码

这个模版类用来封装 nil ptr,让 nil 指针像 non-nil 指针那样正常运行它的操作,而不会让程序崩溃。

// DisguisedPtr acts like pointer type T*, except the 
// DisguisedPtr 的作用类似指针类型 T*,

// stored value is disguised to hide it from tools like `leaks`.
// 除了将存储的值隐藏起来,使其不受 `leaks` 之类的工具的影响。

// nil is disguised as itself so zero-filled memory works as expected, 
// nil 被伪装成它自己,这样零填充的内存也能如预期那样工作,

// which means 0x80..00 is also disguised as itself but we don't care.
// 意思是 Ox80...00 也伪装成它自己,但是我们不在乎。

// Note that weak_entry_t knows about this encoding.
// 注意 weak_entry_t 知道这种编码。

template 
class DisguisedPtr {
    // typedef unsigned long uintptr_t;
    // 无符号 long 类型的 value 成员变量
    uintptr_t value;

    static uintptr_t disguise(T* ptr) { // 指针隐藏
        // 相当于直接把 T 指针的地址转化为 unsigned long 并取负值
        return -(uintptr_t)ptr;
    }

    static T* undisguise(uintptr_t val) { // 指针显示
        // 把 val 转为指针地址,对应上面的 disguise 函数
        return (T*)-val;
    }

 public:
    DisguisedPtr() { } // 构造函数

    // 初始化列表,显式初始化 value 成员变量
    DisguisedPtr(T* ptr) : value(disguise(ptr)) { } // 指针隐藏
    DisguisedPtr(const DisguisedPtr& ptr) : value(ptr.value) { }

    // T* 赋值函数
    DisguisedPtr& operator = (T* rhs) {
        value = disguise(rhs);
        return *this;
    }

    // 引用赋值函数
    DisguisedPtr& operator = (const DisguisedPtr& rhs) {
        value = rhs.value;
        return *this;
    }

    // 重载运算符
    operator T* () const {
        // 转为指针
        return undisguise(value);
    }
    T* operator -> () const { 
        // 转为指针
        return undisguise(value);
    }
    T& operator * () const { 
        // 转化为指针并取出该指针指向的内容
        return *undisguise(value);
    }
    T& operator [] (size_t i) const {
        return undisguise(value)[i];
    }

    // pointer arithmetic operators omitted 
    // 省略的指针算术运算符
    // because we don't currently use them anywhere
    // 因为目前我们不在任何地方使用它
};

// fixme type id is weird and not identical to objc_object*
static inline bool operator == (DisguisedPtr lhs, id rhs) {
    return lhs == (objc_object *)rhs;
}
static inline bool operator != (DisguisedPtr lhs, id rhs) {
    return lhs != (objc_object *)rhs;
}
复制代码

参考链接:

  • 使用intptr_t和uintptr_t
  • Object Runtime -- Weak
  • OC Runtime之Weak(2)---weak_entry_t
  • iOS 关联对象 - DisguisedPtr
  • Objective-C运行时-动态特性
  • Objective-C runtime机制(7)——SideTables, SideTable, weak_table, weak_entry_t

推荐阅读:
1.直击2020——iOS 面试题大全(补充完整版)

2.“新”携程,阿里,腾讯iOS面试常见问题合集(附答案)

作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:761407670 进群密码000,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!

你可能感兴趣的:(iOS weak 底层实现原理(一):DisguisedPtr)