原文:https://juejin.im/post/6865468675940417550
DisguisedPtr
为了全面透彻的理解 weak 关键字,现在从最底层的数据结构开始挖掘,力求构建一个完整的认知体系。
定义位于: Project Headers/objc-private.h
Line 904
指针伪装模版类 Disguised<T>
,与此对应的概念是指针伪装。
DisguisedPtr<T>
通过运算使指针隐藏于系统工具(如 leaks
工具),同时保持指针的能力,其作用是通过计算把保存的 T 的指针隐藏起来,实现指针到整数的映射。
根据 Disguised
这个英文单词我们或许能猜出一部分信息,Ptr
是 Pointer
(指针)的缩写,硬翻译的话可以理解为:掩藏指针
,封装指针
,看它的定义再直白一点的话,大概就是指针本身的地址值与 unsigned long
来回相互转化。
Disguised /dɪs'ɡaɪz/
vt. 假装;掩饰;隐瞒
n. 伪装;假装;用作伪装的东西
复制代码
这个模版类用来封装 nil ptr
,让 nil
指针像 non-nil
指针那样正常运行它的操作,而不会让程序崩溃。
// DisguisedPtr<T> acts like pointer type T*, except the
// DisguisedPtr<T> 的作用类似指针类型 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 <typename T>
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<T>& ptr) : value(ptr.value) { }
// T* 赋值函数
DisguisedPtr<T>& operator = (T* rhs) {
value = disguise(rhs);
return *this;
}
// 引用赋值函数
DisguisedPtr<T>& operator = (const DisguisedPtr<T>& 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<objc_object> lhs, id rhs) {
return lhs == (objc_object *)rhs;
}
static inline bool operator != (DisguisedPtr<objc_object> 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 面试题大全(补充完整版)
作为一个开发者,有一个学习的氛围跟一个交流圈子特别重要,这是一个我的iOS交流群:761407670 进群密码000,不管你是小白还是大牛欢迎入驻 ,分享BAT,阿里面试题、面试经验,讨论技术, 大家一起交流学习成长!