基本上每一个面试都会问weak的实现原理,还有循环引用时候用到weak,今天我们就来研究下weak的实现原理到底是什么。
weak入口
我们在这里打个断点,然后进入汇编调试。
这里就很明显看到了入口,objc_initWeak,接下来就进入objc的源码。官网链接,直接下载最新的。
在源码内顺序为objc_initWeak-->storeWeak-->weak_unregister_no_lock。下面为大致流程,内部还有些判断条件省略了。
从SideTable散列表中找到弱引用表,从弱饮用表中获取weak_entry_t,根据有无weak_entry_t判断是否加入表或者新建weak_entry_t
这就是weak引用的时候,接下来当对象释放的时候,为什么weak修饰的对象指针被置为nil。所以入口就是在dealloc函数中了。
释放
同样,我们在对象的dealloc搭上断点,汇编跟踪,最后进入了objc_destructInstance这个函数。
进入源码,先判断是否有对象,再判断是c++析构函数,是否有关联对象再分对应的操作,之后就是跟weak有关的clearDeallocating
/************************************************************************ objc_destructInstance* Destroys an instance without freeing memory. * Calls C++ destructors.* Calls ARC ivar cleanup.* Removes associative references.* Returns `obj`. Does nothing if `obj` is nil.**********************************************************************/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);obj->clearDeallocating();}return obj;}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());}
内部会调用sidetable_clearDeallocating,这里是根据对象找到对应的弱引用表,再进入weak_clear_no_lock
void objc_object::sidetable_clearDeallocating(){SideTable& table = SideTables()[this];// clear any weak table items// clear extra retain count and deallocating bit// (fixme warn or abort if extra retain count == 0 ?)table.lock();RefcountMap::iterator it = table.refcnts.find(this);if (it != table.refcnts.end()) {if (it->second & SIDE_TABLE_WEAKLY_REFERENCED) {weak_clear_no_lock(&table.weak_table, (id)this);}table.refcnts.erase(it);}table.unlock();}
这里就是具体的释放了,先找到entry结构体数组,再遍历将referrer对象置为nil,最后移除弱引用表。
void weak_clear_no_lock(weak_table_t *weak_table, id referent_id) {objc_object *referent = (objc_object *)referent_id;weak_entry_t *entry = weak_entry_for_referent(weak_table, referent);if (entry == nil) {/// XXX shouldn't happen, but does with mismatched CF/objc//printf("XXX no entry for clear deallocating %p\n", referent);return;}// zero out referencesweak_referrer_t *referrers;size_t count;if (entry->out_of_line()) {referrers = entry->referrers;count = TABLE_SIZE(entry);} else {referrers = entry->inline_referrers;count = WEAK_INLINE_COUNT;}for (size_t i = 0; i < count; ++i) {objc_object **referrer = referrers[i];if (referrer) {if (*referrer == referent) {*referrer = nil;}else if (*referrer) {_objc_inform("__weak variable at %p holds %p instead of %p. ""This is probably incorrect use of ""objc_storeWeak() and objc_loadWeak(). ""Break on objc_weak_error to debug.\n", referrer, (void*)*referrer, (void*)referent);objc_weak_error();}}}weak_entry_remove(weak_table, entry);}
总结
weak的原理就是,在对象释放的时候,会根据对象地址,从弱引用表中找到entry数组,遍历置为nil
如果觉得《iOS进阶之底层原理-weak实现原理》对你有帮助,请点赞、收藏,并留下你的观点哦!