oc 基础 - Category

111 阅读3分钟
  1. category 的实现原理

    1. 底层结构是category_t 结构体 存储了 列方法 实例方法 属性 协议
      在程序运行的时候回将这些合并到类对象中 元类对象中
  2. category 和 extension 的区别是设么

Class extension 在编译的时候他的数据就已经包好在类信息中 category 是在运行时 才会将数据合并

  1. category 中有load 方法吗 ? load 方法什么时候调用的 ?load 方法能继承吗 ?

  2. load initalize 方法的区别是什么?他们在category 中的调用顺序是什么?以及出现继承时他们之间的调用过程

调用方式的区别, load 是根据函数地址直接调用, initalize 是通过msgsen 调用, load 是在加载时 调用仅仅调用一次 调用时刻 initalize 是第一次接收消息的时候调用吗只会调用一次, 父类 会被调用多次 调用顺序 load 先调用类 其次调用分类 按照编译顺序 调用子类的load 之前会先调用父类,

initalize

先初始化父类 再初始化子类 (最终可能是调用父类的方法)

  1. category 能否添加成员变量? 如果可以,如何给category添加成员变量 ?

  2. category 使用场合是什么 ?

把一个类拆分 很多个模块

category 中的方法在唯一类对象列表中, 在运行时归过去

分类的底层结构 编译后 会生成 这个结构体变量

struct category_t { const char *name const method_list_t *instance_methods; const method_list_t *class_methods; const struct protocol const struce properties;

}

类对象 分类列表(当前类的所有分类的数组) 把这些方法 放到 class_rw_t

cls = [Person class]

cats = [category_t(test) , category_t(eat)];

** metdodArray 二维数组 [[method,method],[m2,m2],[M3,m3]]

后加进来的方法数组 放到原数组的前边,提高方法选择的优先级

while (i --) { } 因为减减 所以他是从后往前便利 category_t list 按文件的编译顺序,后编译的分类方法在最前边

类扩展 class extension ()

@interface Person ()

{ int _age; }

@end

=================================

#import <objc/runtime.h>

+(void)load { // 不需要导入头文件 也会被调用,只要载进内存 就调用 程序已启动 加载类的时候 load方法 会被调用, 分类中也会被调用,并且不会被优先级阻挡

load 方法不是走的objc_msgsend, 是直接掉用load

源码查找流程 runtime 入口 load_images call_load_methods

whild (class_used > 0) {
    先加载类的 load 方法 再调用分类的 ,和编译顺序无关
    
    如果有继承的 子类 还是会先调用 父类的 load 方法 然后调用 子类的 load
    然后调用父类的分类, 最后调用子类的分类 按编译顺序
    
    通过类的 load_method 函数地址 的指针 直接调用 只调用一次
}

}

  • (void)initialize { 在这个类第一次接受到消息的时候调用 [Person alloc]; initialize 也是通过objc_msgsend 调用的 只调用一次 会优先掉用父类的initialize 方法 ,如果父类调用过 不会重复调用

    objc_msgsend 内部会调用 initialize 方法 通过汇编实现的

    如果子类没有实现 initialize 方法 也会调用父类的initialize (并且会被多次调用)

    if (自己没有初始化) { if (父类没有初始化) { objc_msgsend(@selected(initalize)) } objc_msgsend(@selected(initalize)) }

}