-
category 的实现原理
- 底层结构是category_t 结构体 存储了 列方法 实例方法 属性 协议
在程序运行的时候回将这些合并到类对象中 元类对象中
- 底层结构是category_t 结构体 存储了 列方法 实例方法 属性 协议
-
category 和 extension 的区别是设么
Class extension 在编译的时候他的数据就已经包好在类信息中 category 是在运行时 才会将数据合并
-
category 中有load 方法吗 ? load 方法什么时候调用的 ?load 方法能继承吗 ?
-
load initalize 方法的区别是什么?他们在category 中的调用顺序是什么?以及出现继承时他们之间的调用过程
调用方式的区别, load 是根据函数地址直接调用, initalize 是通过msgsen 调用, load 是在加载时 调用仅仅调用一次 调用时刻 initalize 是第一次接收消息的时候调用吗只会调用一次, 父类 会被调用多次 调用顺序 load 先调用类 其次调用分类 按照编译顺序 调用子类的load 之前会先调用父类,
initalize
先初始化父类 再初始化子类 (最终可能是调用父类的方法)
-
category 能否添加成员变量? 如果可以,如何给category添加成员变量 ?
-
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)) }
}