一个weak变量是怎样被添加到弱引用表当中的?
可以通过弱引用对象进行哈希算法的计算,然后计算查找它对应的位置
//使用__weak修饰的obj1变量指向obj,此时有了__weak弱引用指针
id __weak obj1 = obj;
| 经过编译之后变成下面
id obj1;
objc_initWeak(&obj1,obj); //实际上是使用objc_initWeak函数(弱引用变量的地址,被修饰的对象)
下面看下上面发生了什么过程
objc_initWeak函数会调用storeWeak函数,然后调用weak_register_no_lock函数
weak指针被添加到弱引用表的具体实现是在weak_register_no_lock中实现的
源码分析
//参数-弱引用变量,被弱引用的对象
id
objc_initWeak(id *location, id newObj)
{
if (!newObj) {
*location = nil;
return nil;
}
//老对象,新对象,在dealloc中是否可以被crash
return storeWeak<false/*old*/, true/*new*/, true/*crash*/>
(location, (objc_object*)newObj);
}
storeWeak(id *location, objc_object *newObj)
{
assert(HaveOld || HaveNew);
if (!HaveNew) assert(newObj == nil);
Class previouslyInitializedClass = nil;
id oldObj;
SideTable *oldTable;
SideTable *newTable;
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;
}
if (HaveNew && newObj) {
//根据当前对象获取它的isa指针来找到它的类对象
Class cls = newObj->getIsa();
//对类对象进行一个是否已经初始化f过的判断
if (cls != previouslyInitializedClass &&
!((objc_class *)cls)->isInitialized())
{
SideTable::unlockTwo<HaveOld, HaveNew>(oldTable, newTable);
_class_initialize(_class_getNonMetaClass(cls, (id)newObj));
previouslyInitializedClass = cls;
goto retry;
}
}
if (HaveOld) {
weak_unregister_no_lock(&oldTable->weak_table, oldObj, location);
}
if (HaveNew) {
//weak_register_no_lock参数:从对象所属的side_table取出弱引用表的地址,被弱引用指向的原对象,弱引用指针,对象在废弃h过程中的标志位
newObj = (objc_object *)weak_register_no_lock(&newTable->weak_table,
(id)newObj, location,
CrashIfDeallocating);
//如果新对象是有值得并且不是小对象的这种管理方式,就设置它为有弱引用的标志位
if (newObj && !newObj->isTaggedPointer()) {
newObj->setWeaklyReferenced_nolock();
}
*location = (id)newObj;
}
//weak_table,原来的对象,弱引用指针,crashIfDeallocating
weak_register_no_lock(weak_table_t *weak_table, id referent_id,
id *referrer_id, bool crashIfDeallocating){
//通过原对象指针去弱引用表中查找所对应的弱引用的数组entry
if ((entry = weak_entry_for_referent(weak_table, referent))) {
append_referrer(entry, referrer);
}
else {
//新创建弱引用数组,把对应位置置为nil
weak_entry_t new_entry;
new_entry.referent = referent;
new_entry.out_of_line = 0;
new_entry.inline_referrers[0] = referrer;
for (size_t i = 1; i < WEAK_INLINE_COUNT; i++) {
new_entry.inline_referrers[i] = nil;
}
weak_grow_maybe(weak_table);
//把弱引用数组插到弱引用表的对应位置中
weak_entry_insert(weak_table, &new_entry);
}
}
static weak_entry_t *
weak_entry_for_referent(weak_table_t *weak_table, objc_object *referent)
{
assert(referent);
//通过弱引用表weak_table获取弱引用数组
weak_entry_t *weak_entries = weak_table->weak_entries;
if (!weak_entries) return nil;
//然后通过原对象的指针地址,进行哈希算法计算,获取到对象在弱引用表中的对应索引位置
size_t index = hash_pointer(referent) & weak_table->mask;
size_t hash_displacement = 0;
//哈希冲突算法,如果我们在对应位置获取到的对象,不是当前所要查找的对象,会根据冲突算法进行索引位置的移动,直到找到真正的对应对象的索引位置,再将查到的索引位置返回给调用方的数组当
while (weak_table->weak_entries[index].referent != referent) {
index = (index+1) & weak_table->mask;
hash_displacement++;
if (hash_displacement > weak_table->max_hash_displacement) {
return nil;
}
}
return &weak_table->weak_entries[index];
}
当一个对象被废弃之后,weak变量是如何处理的?
会被自动置为nil
在调dealloc后,经过一系列的调用,在内部最终会调用weak_clear_no_lock()函数,
weak_clear_no_lock内部会根据当前对象指针查找弱引用表,把当前对象相对应的弱引用位置拿出来,是一个数组,然后遍历数组,遍历所有的弱引用指针,分别置为nil
网友评论