1. 從匯編探索weak
我們常用weak
來進行弱引用對象,是因為它在釋放的時候自動置空胳蛮,打破循環(huán)引用销凑。
從
debug
→Debug Workfkow
→Always Show Disassembly
打開匯編調(diào)試,運行代碼:我們看到進行弱引用的時候調(diào)用了
objc_initWeak
方法仅炊,于是我們可以在添加一個符號斷點:添加符號斷點后斗幼,繼續(xù)往下調(diào)試,發(fā)現(xiàn)方法調(diào)用在
libobjc.A.dylib
庫內(nèi):于是抚垄,我們可以下載
objc
源碼進行后面的探索蜕窿。
2.源碼解析
打開源碼,發(fā)現(xiàn)objc_initWeak
內(nèi)調(diào)用了storeWeak
函數(shù):
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);
// weak_register_no_lock returns nil if weak store should be rejected
// Set is-weakly-referenced bit in refcount table.
if (newObj && !newObj->isTaggedPointer()) {
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);
return (id)newObj;
}
從源碼可看出呆馁,先對是否含有舊值新值做了判斷處理桐经,然后我們拿到一張散列表SideTable
,這個散列表里維護了我們需要的weakTable
智哀。當有舊值的時候次询,調(diào)用weak_unregister_no_lock
從oldTable
內(nèi)取出weakTable
和weak_entry_t
,并進行remove:
當存在新值的時候,調(diào)用
weak_register_no_lock
函數(shù)從newTable
取出weakTable
:首先判斷對象是否正在進行釋放瓷叫,如果正在進行釋放則返回
nil
屯吊。然后,我們從weakTable
內(nèi)取出weak_entry_t
摹菠,如果有值盒卸,則進行拼接到weakTable
內(nèi),如果沒有值次氨,則會自己創(chuàng)建一個weak_entry_t
蔽介,在插入到weakTable
。最后煮寡,在返回一個新的對象虹蓄。
3 總結(jié)
1.通過SideTable找到weak_table;
2.weak_table根據(jù)referent找到或者創(chuàng)建weak_entry_t;
3.然后append_referrer(entry,referrer)將新弱引用的對象添加進去entry幸撕;
4.最后weak_entry_insert把entry加入到我們的weak_table薇组;
5.返回newObj。