【iOS内存管理】weak指针的原理

1、__strong__weak__unsafe_unretained的比较

-(void)viewDidLoad { // 强引用 ,离开打印 @“end” 后的大括号才销毁 __strong Person *person1; // 弱引用,防止野指针 __weak Person *person2; // 弱引用,会造成野指针(不安全) __unsafe_unretained Person *person3; NSLog(@"start"); { Person *person = [[Person alloc] init]; // 强引用 离开打印 @“end” 后的大括号才销毁 Person1 = person; // 离开所在作用域就置为 nil person2 = person; // 括号外调用会报错,造成了野指针, person3 = person; } NSLog(@"end", person3 ); }@end

2、weak是怎么实现的,看底层源码,
  • 进入NSObject.mm
objc_object::rootDealloc() { if (isTaggedPointer()) return; // fixme necessary?if (fastpath(isa.nonpointer&& !isa.weakly_referenced&&// 没有weak引用 !isa.has_assoc&&// 没有关联对象 !isa.has_cxx_dtor&&// 没有C++析构函数 !isa.has_sidetable_rc)) // 里面存储了引用计数,还有个弱引用表(散列表) { assert(!sidetable_present()); free(this); } else { object_dispose((id)this); // 这时候会走这里 , } }

  • 进入 object_dispose()
id object_dispose(id obj) { if (!obj) return nil; objc_destructInstance(obj); free(obj); return nil; }

  • 进入 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); obj->clearDeallocating(); //将指向当前对象的弱指针置为nil }return obj; }

  • 进入 clearDeallocating ()
inline void objc_object::clearDeallocating() { if (slowpath(!isa.nonpointer)) { // Slow path for raw pointer isa. sidetable_clearDeallocating(); } else if (slowpath(isa.weakly_referenced||isa.has_sidetable_rc)) { // Slow path for non-pointer isa with weak refs and/or side table data. clearDeallocating_slow(); }assert(!sidetable_present()); }

  • 进入clearDeallocating_slow ()
NEVER_INLINE void objc_object::clearDeallocating_slow() { assert(isa.nonpointer&&(isa.weakly_referenced || isa.has_sidetable_rc)); SideTable& table = SideTables()[this]; table.lock(); if (isa.weakly_referenced) { weak_clear_no_lock(&table.weak_table, (id)this); } if (isa.has_sidetable_rc) { table.refcnts.erase(this); } table.unlock(); }

  • 进入 objc-weak.mm 源代码:
void weak_unregister_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id) { objc_object *referent = (objc_object *)referent_id; objc_object **referrer = (objc_object **)referrer_id; weak_entry_t *entry; if (!referent) return; if ((entry = weak_entry_for_referent(weak_table, referent))) { remove_referrer(entry, referrer); bool empty = true; if (entry->out_of_line()&&entry->num_refs != 0) { empty = false; } else { for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) { if (entry->inline_referrers[i]) { empty = false; break; } } }if (empty) { weak_entry_remove(weak_table, entry); } } }

【【iOS内存管理】weak指针的原理】我们可以看到,它最终将那些存储到一个哈希表里面的弱引用。到时候这个对象要销毁,它就取出这个对象的弱引用表,把弱引用都给清除掉。
3、ARC 都帮我们做了什么? 是 LLVMrunTime 系统相互协作的一个结果,
LLVM 编绎器帮我们补个 [obj release] ,[obj retain]等引用增减方法。

    推荐阅读