美文网首页
类的加载(三)

类的加载(三)

作者: _涼城 | 来源:发表于2020-10-30 11:22 被阅读0次
类扩展
类扩展 VS 分类

category

  • 专门用来给类添加新的方法
  • 不能给类添加成员属性,添加了成员变量,也无法取到
  • 分类中用property定义变量,只会生成变量的gettersetter方法的声明,不能生成方法实现和带下划线的成员变量 。

extension

  • 可以说成是特殊的分类,也称作匿名分类
  • 可以给类添加成员属性,但是是私有变量
  • 可以给类添加方法,也是私有方法
类扩展探索

main.m中实现Teacher类的扩展,通过Clang进行编译

查看Teacher类拓展的方法,在编译过程中,方法就直接添加到了 methodlist中,作为类的一部分,即编译时期直接添加到本类里面

static struct /*_method_list_t*/ {
    unsigned int entsize;  // sizeof(struct _objc_method)
    unsigned int method_count;
    struct _objc_method method_list[8];
} _OBJC_$_INSTANCE_METHODS_Teacher __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_objc_method),
    8,
    {{(struct objc_selector *)"ext_instanceMethod", "v16@0:8", (void *)_I_Teacher_ext_instanceMethod},
    {(struct objc_selector *)"ext_classMethod", "v16@0:8", (void *)_I_Teacher_ext_classMethod},
    {(struct objc_selector *)"instanceMethod", "v16@0:8", (void *)_I_Teacher_instanceMethod},
    {(struct objc_selector *)"classMethod", "v16@0:8", (void *)_I_Teacher_classMethod},
    {(struct objc_selector *)"ext_name", "@16@0:8", (void *)_I_Teacher_ext_name},
    {(struct objc_selector *)"setExt_name:", "v24@0:8@16", (void *)_I_Teacher_setExt_name_},
    {(struct objc_selector *)"ext_name", "@16@0:8", (void *)_I_Teacher_ext_name},
    {(struct objc_selector *)"setExt_name:", "v24@0:8@16", (void *)_I_Teacher_setExt_name_}}
};
关联对象

在分类中通过runtime关联对象

@interface Person (caterogy)
@property (nonatomic, copy) NSString *cate_name;
@property (nonatomic, assign) int cate_age;
@end

@implementation LGPerson (LG)

- (void)setCate_name:(NSString *)cate_name{
    /**
     1: 对象
     2: 标识符
     3: value
     4: 策略
     */
    objc_setAssociatedObject(self, "cate_name", cate_name, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

- (NSString *)cate_name{
    return  objc_getAssociatedObject(self, "cate_name");
}

@end
设值流程
objc_setAssociatedObject

调用SetAssocHook.get(),实际上是调用_base_objc_setAssociatedObject函数


//实际调用的方法
static void
_base_objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
{
  _object_set_associative_reference(object, key, value, policy);
}

static ChainedHookFunction<objc_hook_setAssociatedObject> SetAssocHook{_base_objc_setAssociatedObject};

void
objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy)
{
    SetAssocHook.get()(object, key, value, policy);
}

_object_set_associative_reference
  1. 创建一个 AssociationsManager 管理类

  2. 获取唯一的全局静态哈希Map:AssociationsHashMap

  3. 判断是否插入的关联值value是否存在,不存在则走关联对象插入空流程

  4. 通过try_emplace方法,并创建一个空的 ObjectAssociationMap 去取查询的键值对:

  5. 如果发现没有这个 key插入一个 空的 BucketT进去并返回true

  6. 通过setHasAssociatedObjects方法标记对象存在关联对象即置isa指针has_assoc属性为true

  7. 用当前 policy 和 value 组成了一个 ObjcAssociation 替换原来 BucketT 中的空

  8. 标记一下 ObjectAssociationMap第一次false

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));
    // 包装了一下 对象
    DisguisedPtr<objc_object> disguised{(objc_object *)object};
    // 包装一下 policy - value
    ObjcAssociation association{policy, value};

    // retain the new value (if any) outside the lock.(retain 引用计数+1,copy 发送消息)
    association.acquireValue();

    {

        //初始化
        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 */
                object->setHasAssociatedObjects();
            }

            /* 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);

                    }
                }
            }
        }
    }

    // release the old value (outside of the lock).
    association.releaseHeldValue();
}
关联对象插入空流程
  1. 根据DisguisedPtr 找到AssociationsHashMap中的iterator迭代查询器
  2. 清理迭代器
  3. 如果插入空值相当于删除
AssocaitionsHashMap
  • Buckets
  • NumEntries
  • NumTombstones
  • NumBuckets
Buckets
  • Bucket
    • DisguisedPtr --- ObjectAssociationMap

相关文章

  • 类加载的原理

    Java类加载器 类加载器可以分为三类: 启动类加载器(Bootstrap ClassLoader):负责加载\l...

  • java类加载器及其原理

    java类加载器 : java中默认有三种类加载器:引导类加载器,扩展类加载器,系统类加载器(也叫应用类加载器) ...

  • JAVAEE中的JAVA基础加强——类加载器、注解、动态代理

    类加载器 什么是类加载器,作用是什么? 类加载器就加载字节码文件(.class) 类加载器的种类 类加载器有三种,...

  • 类加载机制(三)

    加载机制系列类加载机制(一)类加载机制(二)类加载机制(三)类加载器 这里引用尚学堂的的几张图片 demo: 结果:

  • 类加载机制(一)

    加载机制系列类加载机制(一)类加载机制(二)类加载机制(三) 类加载机制 1.JVM把class文件加载到内存,对...

  • 类加载机制(二)

    加载机制系列类加载机制(一)类加载机制(二)类加载机制(三)类的加载全过程中的主动引用与被动引用 类的主动引用(会...

  • 创建一个java.lang.Test类,能被加载吗?

    java中类加载器有三种: Bootstrap类加载器 负责加载java的核心类包,比如rt.jar 拓展类加载...

  • JVM随笔(二) 类加载子系统

    简单来说类加载子系统 = 三层类加载 + 双亲委派 类加载器 JVM中类加载器分为两种由C++编写的类加载器以...

  • java中的ClassLoader

    java类加载流程 java jvm系统自带三个类加载 BootStrap ClassLoader最顶层的类加载器...

  • 类加载机制

    类的加载在JVM中有三个阶段:加载、链接、初始化,这三个阶段都在类加载子系统中完成 类加载器子系统负责加载本地或网...

网友评论

      本文标题:类的加载(三)

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