IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> iOS开发底层之类加载下 (关联对象) - 14 -> 正文阅读

[移动开发]iOS开发底层之类加载下 (关联对象) - 14


前言

  1. ro rw rwe的补充?
    ro (干净内存,只读) -》 rw (脏内存,昂贵,所以需要优化) -》 rwe 。
    之所以会有rw,是因为运行时功能,会修改内存,这时候因为Ro只读,不能修改,所以产生了rw, 用来去追踪, 如果在运行时操作了分类,动态添加方法, 会浪费很多内存,但有的类是不会通过运行时去进行分类,去动态添加方法,所以有了 rwe , 里面存放运行时添加的分类,属性,协议等。 对rw的一个extension。
  2. 本节主要讲的内容为分类的扩展

一、分类什么时候加载?

  1. 根据attachCategories方法,去反推,哪些地方调用了这个方法。
    最终推导出来只有attachToClass 方法调用。

二、attachCategories

项目新建好分类,并写上load方法, 在所有的这个方法处,打上断点,观察执行顺序。 多种情况说明

分类 + 类搭配加载

  1. 两个都有load方法: _read_images 懒加载类 -》 realizeClassWithoutSwift -》 load_categories_nolock -》 attachCategories

  2. 分类没有load方法, 主类有load方法
    _read_images -》 realizeClassWithoutSwift -》 methodizeClass -》 attachToClass ==没有走attachCategories 方法。 ==

  3. 分类有load 方法, 主类没有load方法
    _read_images -》 realizeClassWithoutSwift -》 methodizeClass -》 attachToClass ==没有走attachCategories 方法。 ==

  4. 两个都没有load方法
    直接到main函数了,说明方法都没有执行,走了懒加载流程了。

总结:4种情况:

  1. 非懒加载类 + 非懒加载类
    _getObjc2NonlazyClassList -》 readClass - 》 realizeClassWithoutSwift -》 methodizeClass -》 load_categories_nolock --》 attachToClass -》 attachCategories
  2. 懒加载类 + 非懒加载分类: 会迫使类成为非懒加载类提前加载数据。
  3. 懒加载类 + 懒加载分类: 消息第一次调用,才会加载数据。
  4. 非懒加载类 + 懒加载分类: read_image就开始加载数据。

三、 类扩展、分类 应用层

1. category:分类

  1. 专门用来给类添加新的方法。
  2. 不能给类添加成员属性, 添加了成员变量,也无法取到。
  3. 但我们可以通过runtime去给分类添加属性。
  4. 分类中用@perperty定义变量, 只会生成getter,setter的方法申明, 不能生成方法实现和带下划线的成员变量。

2. extension:扩展

  1. 特殊的分类,匿名分类。
  2. 可以添加成员属性,是私有变量
  3. 可以给类添加方法, 是私有方法

3 .关联对象 (AssociatedObject)

  1. 方法为 _object_set_associative_reference 。 源码如下。
/**
 关联对象 : 存储 object - cate_name -> value - policy
 */
void
_object_set_associative_reference(id object, const void *key, id value, uintptr_t policy)
{
    // This code used to work when nil was passed for object and key. Some code
    // probably relies on that to not crash. Check and handle it explicitly.
    // rdar://problem/44094390
    if (!object && !value) return;

    if (object->getIsa()->forbidsAssociatedObjects())
        _objc_fatal("objc_setAssociatedObject called on instance (%p) of class %s which does not allow associated objects", object, object_getClassName(object));
	//这是将object强转成objc_object类型,得到DisguisedPtr<objc_object>类型的对象disguised
	// 或者是这样: DisguisedPtr<objc_object> disguised = (objc_object *)object
    DisguisedPtr<objc_object> disguised{(objc_object *)object};
    ObjcAssociation association{policy, value};

    // retain the new value (if any) outside the lock.
    association.acquireValue();

    bool isFirstAssociation = false;
    {
        AssociationsManager manager;
        AssociationsHashMap &associations(manager.get());

        if (value) {
        
            auto refs_result = associations.try_emplace(disguised, ObjectAssociationMap{});
            if (refs_result.second) {
                /* it's the first association we make */
                isFirstAssociation = true;
            }

            /* establish or replace the association */
            auto &refs = refs_result.first->second;
            auto result = refs.try_emplace(key, std::move(association));
            if (!result.second) {
                association.swap(result.first->second);
            }
        } else {
            auto refs_it = associations.find(disguised);
            if (refs_it != associations.end()) {
                auto &refs = refs_it->second;
                auto it = refs.find(key);
                if (it != refs.end()) {
                    association.swap(it->second);
                    refs.erase(it);
                    if (refs.size() == 0) {
                        associations.erase(refs_it);

                    }
                }
            }
        }
    }

    // Call setHasAssociatedObjects outside the lock, since this
    // will call the object's _noteAssociatedObjects method if it
    // has one, and this may trigger +initialize which might do
    // arbitrary stuff, including setting more associated objects.
    if (isFirstAssociation)
        object->setHasAssociatedObjects();

    // release the old value (outside of the lock).
    association.releaseHeldValue();
}

源码解读: objc_setAssociatedObject需要传入4个参数,分别是被关联者,关联标记,关联对象的值和关联策略。
核心流程为: 代码中先创建了AssociationsManager对象manager,再获取全局的hashMap表,然后根据value进行处理

4. AssociationsHashMap

  1. 源码如下:
class AssociationsManager {
    using Storage = ExplicitInitDenseMap<DisguisedPtr<objc_object>, ObjectAssociationMap>;
    static Storage _mapStorage;

public:
    AssociationsManager()   { AssociationsManagerLock.lock(); }
    ~AssociationsManager()  { AssociationsManagerLock.unlock(); }

    AssociationsHashMap &get() {
        return _mapStorage.get();
    }

    static void init() {
        _mapStorage.init();
    }
};

源码解读: AssociationsHashMap是通过manager.get()获取HashMap,它的源码是通过_mapStorage调用get()方法实现的,而_mapStorage是一个static类型,所以获取的这张表是唯一的,这个获取表的过程是个单例方法

总结

1. 设值过程

1.创建一个AssociationsManager管理类;
2.得到唯一的全局静态哈希Map;
3.判断要插入的关联值是否存在:
3.1 存在,则执行4;
3.2 不存在,则进行关联对象插入空流程
4.创建一个空的ObjectAssociationMap去取查询的键值对;
5.如果发现没有这个key,就插入一个空的BucketT,并返回;
6.标记对象存在关联对象;
7.用当前 修饰策略 和 值 组成一个ObjcAssociation替换原来BucketT中的空
8.标记一下ObjectAssociationMap的第一次为false;

2. 取值过程

  1. HashMap
  2. 然后根据object获取ObjectAssociationMap bucket
  3. 再获取ObjectAssociationMap
  4. 然后获取ObjcAssociation bucket
  5. 再获取ObjcAssociation
  6. 最后根据policy返回value
  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-08-23 16:48:38  更:2021-08-23 16:48:46 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:43:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码