1、应用举例
分别用strong、weak、__unsafe_unretained指针指向对象,观察对象销毁情况:
- (void)viewDidLoad {
[super viewDidLoad];
__strong Person* person1;
__weak Person* person2;
__unsafe_unretained Person* person3;
NSLog(@"1");
{
Person *person = [[Person alloc] init];
}
NSLog(@"2");
}
没有指针指向person对象,查看打印结果:
~: 1
~: -[Person dealloc]
~: 2
person会在第12行代码执行结束后销毁。
使用__strong指针指向Person对象,查看打印结果:
- (void)viewDidLoad {
[super viewDidLoad];
__strong Person* person1;
__weak Person* person2;
__unsafe_unretained Person* person3;
NSLog(@"1");
{
Person *person = [[Person alloc] init];
person1 = person;
}
NSLog(@"2");
}
~: 1
~: 2
~: -[Person dealloc]
person会在person1销毁后销毁。
换成person2或者person3指向person对象,查看打印结果:
- (void)viewDidLoad {
[super viewDidLoad];
__strong Person* person1;
__weak Person* person2;
__unsafe_unretained Person* person3;
NSLog(@"1");
{
Person *person = [[Person alloc] init];
person2 = person;
}
NSLog(@"2");
}
~: 1
~: -[Person dealloc]
~: 2
person会在第13行代码执行结束后销毁,可以看出弱指针引用不会影响对象的销毁。
weak和unsafe_unretained的区别是weak修饰的指针在被修饰对象销毁时,会自动置为nil,unsafe_unretained则不会,所以__unsafe_unretained是不安全的。
2、weak指针销毁原理
通过查看objc源码:
NSObject.mm
dealloc方法
_objc_rootDealloc方法
objc-object.h
rootDealloc方法
objc-runtime-new.mm
object_dispose方法
objc_destructInstance方法
void *objc_destructInstance(id obj)
{
if (obj) {
// Read all of the flags at once for performance.
bool cxx = obj->hasCxxDtor();
bool assoc = obj->hasAssociatedObjects();
// This order is important.
// 清除成员变量
if (cxx) object_cxxDestruct(obj);
// 清除关联对象
if (assoc) _object_remove_assocations(obj, /*deallocating*/true);
// 将指向当前对象的弱指针置为nil
obj->clearDeallocating();
}
return obj;
}
在对象调用dealloc时,会将指向当前对象的弱指针置为nil。
3、总结
weak指针是存储在SideTable里的weak_table中,也是一个哈希表。
struct SideTable {
spinlock_t slock;
RefcountMap refcnts;
weak_table_t weak_table;
};
当对象销毁时,会从weak_table中找到指向自己的weak指针,将weak指针置为nil。