- weak弱引用代码逻辑实现?
// Update a weak variable. // If HaveOld is true, the variable has an existing value // that needs to be cleaned up. This value might be nil. // If HaveNew is true, there is a new value that needs to be // assigned into the variable. This value might be nil. // If CrashIfDeallocating is true, the process is halted if newObj is // deallocating or newObj's class does not support weak references. // If CrashIfDeallocating is false, nil is stored instead. enum CrashIfDeallocating { DontCrashIfDeallocating = false, DoCrashIfDeallocating = true }; template <HaveOld haveOld, HaveNew haveNew, enum CrashIfDeallocating crashIfDeallocating> static id storeWeak(id *location, objc_object *newObj) { ASSERT(haveOld || haveNew); if (!haveNew) ASSERT(newObj == nil); Class previouslyInitializedClass = nil; id oldObj; SideTable *oldTable; SideTable *newTable; // Acquire locks for old and new values. // Order by lock address to prevent lock ordering problems. // Retry if the old value changes underneath us. retry: if (haveOld) { oldObj = *location; oldTable = &SideTables()[oldObj]; } else { oldTable = nil; } if (haveNew) { newTable = &SideTables()[newObj]; } else { newTable = nil; } SideTable::lockTwo<haveOld, haveNew>(oldTable, newTable); if (haveOld && *location != oldObj) { SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable); goto retry; } // Prevent a deadlock between the weak reference machinery // and the +initialize machinery by ensuring that no // weakly-referenced object has an un-+initialized isa. if (haveNew && newObj) { Class cls = newObj->getIsa(); if (cls != previouslyInitializedClass && !((objc_class *)cls)->isInitialized()) { SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable); class_initialize(cls, (id)newObj); // If this class is finished with +initialize then we're good. // If this class is still running +initialize on this thread // (i.e. +initialize called storeWeak on an instance of itself) // then we may proceed but it will appear initializing and // not yet initialized to the check above. // Instead set previouslyInitializedClass to recognize it on retry. previouslyInitializedClass = cls; goto retry; } } // Clean up old value, if any. if (haveOld) { weak_unregister_no_lock(&oldTable->weak_table, oldObj, location); } // Assign new value, if any. if (haveNew) { newObj = (objc_object *) weak_register_no_lock(&newTable->weak_table, (id)newObj, location, crashIfDeallocating ? CrashIfDeallocating : ReturnNilIfDeallocating); // weak_register_no_lock returns nil if weak store should be rejected // Set is-weakly-referenced bit in refcount table. if (!newObj->isTaggedPointerOrNil()) { newObj->setWeaklyReferenced_nolock(); } // Do not set *location anywhere else. That would introduce a race. *location = (id)newObj; } else { // No new value. The storage is not changed. } SideTable::unlockTwo<haveOld, haveNew>(oldTable, newTable); // This must be called without the locks held, as it can invoke // arbitrary code. In particular, even if _setWeaklyReferenced // is not implemented, resolveInstanceMethod: may be, and may // call back into the weak reference machinery. callSetWeaklyReferenced((id)newObj); return (id)newObj; } /** * This function stores a new value into a __weak variable. It would * be used anywhere a __weak variable is the target of an assignment. * * @param location The address of the weak pointer itself * @param newObj The new object this weak ptr should now point to * * @return \e newObj */ id objc_storeWeak(id *location, id newObj) { return storeWeak<DoHaveOld, DoHaveNew, DoCrashIfDeallocating> (location, (objc_object *)newObj); }
-
weak的自动设置为nil是怎么实现的?
//一个对象的销毁的调用轨迹是 dealloc _objc_rootDealloc rootDealloc object_dispose objc_destructInstance free
- SideTable结构是怎样的?
struct SideTable { spinlock_t slock; RefcountMap refcnts; weak_table_t weak_table; SideTable() { memset(&weak_table, 0, sizeof(weak_table)); } ~SideTable() { _objc_fatal("Do not delete SideTable."); } void lock() { slock.lock(); } void unlock() { slock.unlock(); } void forceReset() { slock.forceReset(); } // Address-ordered lock discipline for a pair of side tables. template<HaveOld, HaveNew> static void lockTwo(SideTable *lock1, SideTable *lock2); template<HaveOld, HaveNew> static void unlockTwo(SideTable *lock1, SideTable *lock2); };