美文网首页
__weak原理

__weak原理

作者: George_Luofz | 来源:发表于2018-04-09 18:24 被阅读35次
    1. 前言

    我们都知道,__weak修饰的变量会在其指向的对象释放时自动置为nil
    没有前言,文章没法开始

    2. 结论
    • runtime维护了一个全局的hash表,存放所有的weak变量(__weak或者@property(weak)修饰的)
    • hash表的key是weak变量引用对象的地址,value是weak变量的指针数组
    • 当对象引用计数为0也就是释放时,runtime会遍历hash表,将hash表中所有该对象的weak变量置为nil
    2. 探究过程

    参考:iOS 底层解析weak的实现原理(包含weak对象的初始化,引用,释放的分析)
    我们可以结合runtime源码查看其实现逻辑
    我在打断点时,不知道应该断哪几个方法,网上搜了下主要是objc_storeWeak方法,它是由objc_initWeak方法调用的,内部关于weak变量的操作,基本都依赖于objc_storeWeak这个函数,调用堆栈如下:

    objc_storeWeak堆栈
    1. objc_initWeak函数如下:
    objc_initWeak(id *location, id newObj)
    {
        if (!newObj) {
            *location = nil;
            return nil;
        }
    
        return storeWeak<DontHaveOld, DoHaveNew, DoCrashIfDeallocating>
            (location, (objc_object*)newObj);
    }
    
    1. 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(_class_getNonMetaClass(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;
    }
    
    

    大致逻辑就是:

    // 1. 找hash表中是否存有旧值,有的话清空(这个地方相当于一个边界考虑)
    // 2. 找hash表中是否存有新值,有的话更新hash表
    

    先探究到这~

    相关文章

      网友评论

          本文标题:__weak原理

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