weak 原理
- 思路解析:
下载参考链接中的可运行版本,在main.m中加入以下代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
NSObject *p = [[NSObject alloc] init];
//1
__weak NSObject *p1;
//2
p1 = p;
}
return 0;
}
可进行单点调试, 只有第二部真正赋值的时候,调用objc_storeWeak函数
- weak 数据结构
/**
* The global weak references table. Stores object ids as keys,
* and weak_entry_t structs as their values.
*/
struct weak_table_t {
weak_entry_t *weak_entries;
size_t num_entries;
uintptr_t mask;
uintptr_t max_hash_displacement;
};
整个功能的所有的weak变量存储在一张 weak_table_t的哈希表中,哈希表以指针指向的对象为key,以所有指向对象的weak指针数组为value(上述结构体中weak_entries)
//每个weak_entry_t 对象与数组指针对应关系结构体
struct weak_entry_t {
DisguisedPtr<objc_object> referent;
union {
struct {
weak_referrer_t *referrers;
uintptr_t out_of_line_ness : 2;
uintptr_t num_refs : PTR_MINUS_2;
uintptr_t mask;
uintptr_t max_hash_displacement;
};
struct {
// out_of_line_ness field is low bits of inline_referrers[1]
weak_referrer_t inline_referrers[WEAK_INLINE_COUNT];
};
};
bool out_of_line() {
return (out_of_line_ness == REFERRERS_OUT_OF_LINE);
}
weak_entry_t& operator=(const weak_entry_t& other) {
memcpy(this, &other, sizeof(other));
return *this;
}
weak_entry_t(objc_object *newReferent, objc_object **newReferrer)
: referent(newReferent)
{
inline_referrers[0] = newReferrer;
for (int i = 1; i < WEAK_INLINE_COUNT; i++) {
inline_referrers[i] = nil;
}
}
};
/// Adds an (object, weak pointer) pair to the weak table.
id weak_register_no_lock(weak_table_t *weak_table, id referent,
id *referrer, bool crashIfDeallocating);
/**
* Registers a new (object, weak pointer) pair. Creates a new weak
* object entry if it does not exist.
*
* @param weak_table The global weak table.
* @param referent The object pointed to by the weak reference.
* @param referrer The weak pointer address.
*/
id
weak_register_no_lock(weak_table_t *weak_table, id referent_id,
id *referrer_id, bool crashIfDeallocating)
{
objc_object *referent = (objc_object *)referent_id;
objc_object **referrer = (objc_object **)referrer_id;
if (!referent || referent->isTaggedPointer()) return referent_id;
// ensure that the referenced object is viable
bool deallocating;
if (!referent->ISA()->hasCustomRR()) {
deallocating = referent->rootIsDeallocating();
}
else {
BOOL (*allowsWeakReference)(objc_object *, SEL) =
(BOOL(*)(objc_object *, SEL))
object_getMethodImplementation((id)referent,
SEL_allowsWeakReference);
if ((IMP)allowsWeakReference == _objc_msgForward) {
return nil;
}
deallocating =
! (*allowsWeakReference)(referent, SEL_allowsWeakReference);
}
if (deallocating) {
if (crashIfDeallocating) {
_objc_fatal("Cannot form weak reference to instance (%p) of "
"class %s. It is possible that this object was "
"over-released, or is in the process of deallocation.",
(void*)referent, object_getClassName((id)referent));
} else {
return nil;
}
}
// now remember it and where it is being stored
weak_entry_t *entry;
if ((entry = weak_entry_for_referent(weak_table, referent))) {
append_referrer(entry, referrer);
}
else {
weak_entry_t new_entry(referent, referrer);
weak_grow_maybe(weak_table);
weak_entry_insert(weak_table, &new_entry);
}
// Do not set *referrer. objc_storeWeak() requires that the
// value not change.
return referent_id;
}
小结
- weak 生命周期
NSObject *p = [[NSObject alloc] init];
__weak NSObject *p1 = p;
weak表示一个弱引用表,实现为一个weak_table_t结构体,存储了某个对象相关的所有弱引用信息
weak 哈希表 一个项目里面仅有一个;
生成与销毁
使用__weak修饰 指针变量时,调用objc_storeWeak(id *location, id newObj)函数。
当对象释放,weak表操作如下
1、从weak表中获取废弃对象的地址为键值的记录
2、将包含在记录中的所有赋有__weak修饰符变量的地址,赋值为nil.
3、从weak表中删除该记录
4、从引用计数表中删除废弃对象的地址为键值的记录
参见Objective-c高级编程P67
- 实操
{
id __weak obj1= obj;
}
假设obj附加__strong修饰符,且被对象赋值
\*编译器的模拟代码*\
id obj1;
objc_initWeak(&obj1,obj);
objc_destroyWeak(&obj1);
参考链接:
源码链接:https://github.com/cocoa-chen/objc-709
objc - 编译Runtime源可运行版本:https://blog.csdn.net/fishmai/article/details/81041999
weak原理:http://ios.jobbole.com/89012/
weak指针: http://www.cocoachina.com/ios/20170328/18962.html