美文网首页ios底层探索
ios weak底层实现

ios weak底层实现

作者: Jeffery_zc | 来源:发表于2021-01-11 16:13 被阅读0次

    1. 从汇编探索weak

    我们常用weak来进行弱引用对象,是因为它在释放的时候自动置空,打破循环引用。

    step01.png
    debugDebug WorkfkowAlways Show Disassembly打开汇编调试,运行代码:
    step02.png
    我们看到进行弱引用的时候调用了objc_initWeak方法,于是我们可以在添加一个符号断点:
    step03.png
    添加符号断点后,继续往下调试,发现方法调用在libobjc.A.dylib库内:
    step04.png
    于是,我们可以下载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_lockoldTable内取出weakTableweak_entry_t,并进行remove:

    weak_unregister_no_lock.png
    当存在新值的时候,调用weak_register_no_lock函数从newTable取出weakTable
    weak_register_no_lock.png
    首先判断对象是否正在进行释放,如果正在进行释放则返回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。

    相关文章

      网友评论

        本文标题:ios weak底层实现

        本文链接:https://www.haomeiwen.com/subject/uicfaktx.html