__strong TObj *strongObj;
//__weak TObj *weakObj;
//__unsafe_unretained TObj *unsafeObj;
{
TObj *obj = [[TObj alloc] init];
NSLog(@"obj对象:%@", obj);
strongObj = obj;
// weakObj = obj;
// unsafeObj = obj;
}
NSLog(@"strongObj:%@", strongObj);
// NSLog(@"weakObj:%@", weakObj);
// NSLog(@"unsafeObj:%@", unsafeObj);
__strong
修饰后,对象的引用计数会增加,在作用域外不会销毁__weak
修饰后,对象引用计数不会增加,在作用域外会自动置为nil (打印weakObj为null)
__unsafe_unretained
修饰后,兑现引用计数不会增加,在作用域外不会置空,会造成野指针崩溃
一:weak的创建
还是使用刚才的例子,直接跟踪汇编和打符号断点,发现底层库调了objc_initWeak
函数。
objc_initWeak
其中两个参数location
和newObj
的含义如下:
1.location
:表示__weak
指针的地址,即例子中的weak
指针取地址: &weakObjc
。它是一个指针的地址。之所以要存储指针的地址,是因为最后我们要讲__weak
指针指向的内容置为nil
,如果仅存储指针的话,是不能够完成这个功能的。2.newObj
:所引用的对象,即例子中的obj 。
storeWeak
在storeWeak方法中有两个重要的方法,weak_register_no_lock 和 weak_unregister_no_lock。
weak_register_no_lock:如果可以被弱引用,则将被弱引用对象所在的weak_table中
的weak_entry_t
哈希数组中取出对应的weak_entry_t
,如果weak_entry_t
不存在,则会新建一个。然后将指向被弱引用对象地址的指针referrer
通过函数append_referrer
插入到对应的weak_entry_t
引用数组。完成了弱引用
weak_unregister_no_lock:如果weak
指针在指向obj
之前,已经弱引用了其他的对象,则需要先将weak指针从其他对象的weak_entry_t
的hash
数组中移除。在storeWeak
方法中会调用weak_unregister_no_lock
函数来做移除操作。
二:weak的销毁
weak修饰的对象,出作用域,对象dealloc
后,会自动把弱引用对象置空,例如开头的例子。
主要方法有:_objc_rootDealloc, object_dispose,weak_clear_no_lock
weak_clear_no_lock:从sideTble中的weak_table散列表找到对应的weak_entry_t数组,然后通过遍历找到对应的指针地址,置为nil
,防止了野指针的报错。
总结
创建和销毁差不多相同,从sideTble中的weak_table散列表找到对应的weak_entry_t数组,然后通过遍历找到对应的指针地址,置为nil
,防止了野指针的报错,或者插入到weak_entry_t数组。
- 当一个对象obj被weak指针指向时,这个weak指针会以obj作为key,被存储到
sideTable
类的weak_table
这个散列表上对应的一个weak指针数组
里面。 - 当一个对象obj的
dealloc
方法被调用时,Runtime会以obj为key,从sideTable
的weak_table
散列表中,找出对应的weak指针列
表,然后将里面的weak指针逐个置为nil
。