• Objective-C weak深入理解


    1、weak是弱引用,所引用的对象计数不会加1。

    2、weak变量在其引用的对象被销毁之后,会被置为nil。

    3、weak通常用于block, delegate, NSTimer,以解决循环引用带来的内存泄漏问题。

    NSObject *obj = [[NSObject alloc] init]; // obj是被引用对象的指针
    id __weak obj1 = obj; // obj1是weak变量,也是被引用对象的指针

    weak的底层实现,简化的源码及解析如下: 

    id objc_storeWeak(id *location, id newObj) // objc_storeWeak(&obj1, obj)
    {   
        id oldObj;
        SideTable *oldTable;
        SideTable *newTable;
     
        oldObj = *location; // weak变量,也是被引用对象的指针
        // 根据被引用对象的指针的哈希值得到对应的SideTable
        oldTable = SideTable::tableForPointer(oldObj);
        newTable = SideTable::tableForPointer(newObj);
    
        if (oldObj) {
            weak_unregister_no_lock(&oldTable->weak_table, oldObj, location); // 删掉旧引用,因为location要指向newObj,其实应该先判断oldObj != newObj的
        }
        if (newObj) {
            newObj = weak_register_no_lock(&newTable->weak_table, newObj,location); // 添加新引用
        }
        *location = newObj;
    
        return newObj;
    } 
    void weak_unregister_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id)
    {
        objc_object *referent = (objc_object *)referent_id;
        objc_object **referrer = (objc_object **)referrer_id;
    
        weak_entry_t *entry;
        if ((entry = weak_entry_for_referent(weak_table, referent))) {
            remove_referrer(entry, referrer); // 删掉旧的weak变量的指针
            bool empty = true;
            for (size_t i = 0; i < WEAK_INLINE_COUNT; i++) {
                if (entry->inline_referrers[i]) {
                    empty = false; 
                    break;
                }
            }
            if (empty) {
                weak_entry_remove(weak_table, entry); // 如果旧的被引用对象的指针对应的weak变量的指针数组空了,则删掉这个被引用对象的指针
            }
        }
    }
    

       

    id weak_register_no_lock(weak_table_t *weak_table, id referent_id, id *referrer_id)
    {
        // 被引用对象的指针
        objc_object *referent = (objc_object *)referent_id;
        // weak变量的指针
        objc_object **referrer = (objc_object **)referrer_id;
    
        weak_entry_t *entry;
        if ((entry = weak_entry_for_referent(weak_table, referent))) {
            append_referrer(entry, referrer); // 有就往指针数组加一个
        } else {
            weak_entry_t new_entry;
            new_entry.referent = referent;
            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); // 没有就创建一个指针数组,然后加一个
        }
    
        return referent_id;
    }
    class SideTable {
    private:
        static uint8_t table_buf[SIDE_TABLE_STRIPE * SIDE_TABLE_SIZE]; // 所有SideTable对象共用,数组元素是SideTable *。看成全局数组,而不属于某个SideTable对象,更好理解。
    
    public:
        weak_table_t weak_table; // SideTable对象和weak表一一对应
        
        static SideTable *tableForPointer(const void *p) 
        {
            uintptr_t a = (uintptr_t)p;
            int index = ((a >> 4) ^ (a >> 9)) & (SIDE_TABLE_STRIPE - 1);
            return (SideTable *)&table_buf[index * SIDE_TABLE_SIZE];
        }
        
    };
    // weak表
    struct weak_table_t {
        weak_entry_t *weak_entries;
    };
    // weak表项
    struct weak_entry_t {
        DisguisedPtr<objc_object> referent; // 被引用对象的指针
        weak_referrer_t  inline_referrers[WEAK_INLINE_COUNT]; // weak变量的指针数组
    };

    来个直观的整体结构图如下: 

      

    参考链接:

    https://opensource.apple.com/source/objc4/objc4-532/runtime/NSObject.mm.auto.html

    https://opensource.apple.com/source/objc4/objc4-646/runtime/objc-weak.h

  • 相关阅读:
    python实现kNN(最近邻)
    拉格朗日对偶
    拉格朗日乘子法和KKT约束
    python实现支持向量机之具体实现
    python实现支持向量机之非线性支持向量机和核函数(理论五)
    Python 装饰器实例
    Linux 系统下 matplotlib 中文乱码解决办法
    Python logging 模块学习
    Matplotlib 知识点整理
    Python Matplotlib 中文显示参数设置
  • 原文地址:https://www.cnblogs.com/yangwenhuan/p/9226689.html
Copyright © 2020-2023  润新知