美文网首页
底层-Category

底层-Category

作者: Stago | 来源:发表于2020-01-09 10:37 被阅读0次
    • 定义在objc-runtime-new.h中


    Category的加载处理过程

    1.通过Runtime加载某个类的所有Category数据
    2.把所有Category的方法、属性、协议数据,合并到一个大数组中

    后面参与编译的Category数据,会在数组的前面

    3.将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面

    源码解读顺序

    • objc-os.mm
    • _objc_init
    • map_images
    • map_images_nolock
    • objc-runtime-new.mm
    • _read_images
    • remethodizeClass
    • attachCategories
    • attachLists
    • realloc、memmove、 memcpy

    +load方法

    • +load方法会在runtime加载类、分类时调用
    • 每个类、分类的+load,在程序运行过程中只调用一次
    • 调用顺序

    1.先调用类的+load

    按照编译先后顺序调用(先编译,先调用)
    调用子类的+load之前会先调用父类的+load

    2.再调用分类的+load

    按照编译先后顺序调用(先编译,先调用)

    • objc4源码解读过程:objc-os.mm
    • _objc_init
    • load_images
    • prepare_load_methods

    schedule_class_load
    add_class_to_loadable_list
    add_category_to_loadable_list

    • call_load_methods

    call_class_loads
    call_category_loads
    (*load_method)(cls, SEL_load)

    • +load方法是根据方法地址直接调用,并不是经过objc_msgSend函数调用

    +initialize方法

    • +initialize方法会在类第一次接收到消息时调用
    • 调用顺序
    • 先调用父类的+initialize,再调用子类的+initialize
    • (先初始化父类,再初始化子类,每个类只会初始化1次)
    • +initialize和+load的很大区别是,+initialize是通过objc_msgSend进行调用的,所以有以下特点

    如果子类没有实现+initialize,会调用父类的+initialize(所以父类的+initialize可能会被调用多次)
    如果分类实现了+initialize,就覆盖类本身的+initialize调用

    • objc4源码解读过程
    • objc-msg-arm64.s

    objc_msgSend

    • objc-runtime-new.mm

    class_getInstanceMethod
    lookUpImpOrNil
    lookUpImpOrForward
    _class_initialize
    callInitialize
    objc_msgSend(cls, SEL_initialize)

    思考:如何实现给分类“添加成员变量”?

    • 默认情况下,因为分类底层结构的限制,不能添加成员变量到分类中。但可以通过关联对象来间接实现
    • 关联对象提供了以下API
    • 添加关联对象
    void objc_setAssociatedObject(id object, const void * key, id value, objc_AssociationPolicy policy)
    
    • 获得关联对象
    id objc_getAssociatedObject(id object, const void * key)
    
    • 移除所有的关联对象
    void objc_removeAssociatedObjects(id object)
    

    key的常见用法

    • static void *MyKey = &MyKey;
    objc_setAssociatedObject(obj, MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    objc_getAssociatedObject(obj, MyKey)
    
    • static char MyKey;
    objc_setAssociatedObject(obj, &MyKey, value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    objc_getAssociatedObject(obj, &MyKey)
    
    • 使用属性名作为key
    objc_setAssociatedObject(obj, @"property", value, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    objc_getAssociatedObject(obj, @"property");
    
    • 使用get方法的@selecor作为key
    objc_setAssociatedObject(obj, @selector(getter), value, OBJC_ASSOCIATION_RETAIN_NONATOMIC)
    objc_getAssociatedObject(obj, @selector(getter))
    

    objc_AssociationPolicy

    关联对象的原理

    • 实现关联对象技术的核心对象有

    AssociationsManager
    AssociationsHashMap
    ObjectAssociationMap
    ObjcAssociation

    • objc4源码解读:objc-references.mm


    void objc_setAssociatedObject(id object, const void * key,
                                  id value, 
                     objc_AssociationPolicy policy)
    
    • 关联对象并不是存储在被关联对象本身内存中

    • 关联对象存储在全局的统一的一个AssociationsManager中

    • 设置关联对象为nil,就相当于是移除关联对象


    相关文章

      网友评论

          本文标题:底层-Category

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