1. 从汇编探索weak
我们常用weak
来进行弱引用对象,是因为它在释放的时候自动置空,打破循环引用。
从
debug
→Debug Workfkow
→Always Show Disassembly
打开汇编调试,运行代码:我们看到进行弱引用的时候调用了
objc_initWeak
方法,于是我们可以在添加一个符号断点:添加符号断点后,继续往下调试,发现方法调用在
libobjc.A.dylib
库内:于是,我们可以下载
objc
源码进行后面的探索。
2.源码解析
打开源码,发现objc_initWeak
内调用了storeWeak
函数:
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
。当有旧值的时候,调用weak_unregister_no_lock
从oldTable
内取出weakTable
和weak_entry_t
,并进行remove:
当存在新值的时候,调用
weak_register_no_lock
函数从newTable
取出weakTable
:首先判断对象是否正在进行释放,如果正在进行释放则返回
nil
。然后,我们从weakTable
内取出weak_entry_t
,如果有值,则进行拼接到weakTable
内,如果没有值,则会自己创建一个weak_entry_t
,在插入到weakTable
。最后,在返回一个新的对象。
3 总结
1.通过SideTable找到weak_table;
2.weak_table根据referent找到或者创建weak_entry_t;
3.然后append_referrer(entry,referrer)将新弱引用的对象添加进去entry;
4.最后weak_entry_insert把entry加入到我们的weak_table;
5.返回newObj。