1、应用举例

分别用strong、weak、__unsafe_unretained指针指向对象,观察对象销毁情况:

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. __strong Person* person1;
  4. __weak Person* person2;
  5. __unsafe_unretained Person* person3;
  6. NSLog(@"1");
  7. {
  8. Person *person = [[Person alloc] init];
  9. }
  10. NSLog(@"2");
  11. }

没有指针指向person对象,查看打印结果:

  1. ~: 1
  2. ~: -[Person dealloc]
  3. ~: 2

person会在第12行代码执行结束后销毁。
使用__strong指针指向Person对象,查看打印结果:

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. __strong Person* person1;
  4. __weak Person* person2;
  5. __unsafe_unretained Person* person3;
  6. NSLog(@"1");
  7. {
  8. Person *person = [[Person alloc] init];
  9. person1 = person;
  10. }
  11. NSLog(@"2");
  12. }
  1. ~: 1
  2. ~: 2
  3. ~: -[Person dealloc]

person会在person1销毁后销毁。
换成person2或者person3指向person对象,查看打印结果:

  1. - (void)viewDidLoad {
  2. [super viewDidLoad];
  3. __strong Person* person1;
  4. __weak Person* person2;
  5. __unsafe_unretained Person* person3;
  6. NSLog(@"1");
  7. {
  8. Person *person = [[Person alloc] init];
  9. person2 = person;
  10. }
  11. NSLog(@"2");
  12. }
  1. ~: 1
  2. ~: -[Person dealloc]
  3. ~: 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方法

  1. void *objc_destructInstance(id obj)
  2. {
  3. if (obj) {
  4. // Read all of the flags at once for performance.
  5. bool cxx = obj->hasCxxDtor();
  6. bool assoc = obj->hasAssociatedObjects();
  7. // This order is important.
  8. // 清除成员变量
  9. if (cxx) object_cxxDestruct(obj);
  10. // 清除关联对象
  11. if (assoc) _object_remove_assocations(obj, /*deallocating*/true);
  12. // 将指向当前对象的弱指针置为nil
  13. obj->clearDeallocating();
  14. }
  15. return obj;
  16. }

在对象调用dealloc时,会将指向当前对象的弱指针置为nil。

3、总结

weak指针是存储在SideTable里的weak_table中,也是一个哈希表。

  1. struct SideTable {
  2. spinlock_t slock;
  3. RefcountMap refcnts;
  4. weak_table_t weak_table;
  5. };

当对象销毁时,会从weak_table中找到指向自己的weak指针,将weak指针置为nil。