iOS进阶

05-OC中Category的底层原理

2020-06-14  本文已影响0人  光强_上海

Category 本质

category的实现原理?,category的底层数据结构?

我们创建一个Person类,然后创建一个Person+Eat的分类,代码如下:

Person类

@interface Person : NSObject

- (void)run;
@end

@implementation Person

- (void)run {
    NSLog(@"---%s", __func__);
}
@end

Person+Eat分类

@interface Person (Eat)

- (void)eat;
@end

@implementation Person (Eat)

- (void)eat {
    NSLog(@"--%s", __func__);
}
@end

然后我们执行命令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Person+Eat.m,将Person+Eat.m转换为底层c++代码

从转换后的底层c++代码中,我们可以看到分类的数据结构,结构体_category_t如下:

struct _category_t {
    const char *name;
    struct _class_t *cls;
    const struct _method_list_t *instance_methods;
    const struct _method_list_t *class_methods;
    const struct _protocol_list_t *protocols;
    const struct _prop_list_t *properties;
};

_OBJC_$_CATEGORY_Person_$_Eat:此变量就是给_category_t结构体内成员信息进行赋值

static struct _category_t _OBJC_$_CATEGORY_Person_$_Eat __attribute__ ((used, section ("__DATA,__objc_const"))) = 
{
    "Person", // 类名
    0, // &OBJC_CLASS_$_Person, // cls
    (const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_Eat, // 实例方法列表
    0, // 类方法列表
    0, // 协议列表
    0, // 属性列表
};

我们知道运行时机制会将工程中所有的分类都转换为_category_t这种结构体对象,所有分类的信息也都临时存放在_category_t结构体中,然后程序会将所有的分类信息都合并到类对象\元类对象的结构体中,这里合并的信息主要包括如下几个:

  1. 方法列表
  2. 属性列表
  3. 协议列表

运行时的具体合并操作底层源码解读如下图所示:

image

类中的方法和分类中添加的方法的调用顺序?

最后编译的分类,优先放到分类方法数组的最前面,合并后在方法列表的前面,在查找方法调用时,也就会优先调用

OC类文件的编译顺序就是Compile Sources的文件的存放顺序

image

分类中的load方法有什么作用,调用时机和调用顺序?

load方法会在runtime运行时加载类、分类信息时调用,并且每个类\分类的load方法在程序运行过程中只会调用一次

load方法的调用顺序如下图所示:

image

load方法的调用机制是根据方法内存地址直接调用,并不是执行objc_msgSend进行消息发送


分类中的initialize方法的作用,调用时机和调用顺序?

initialize方法会在第一次接收到消息时调用

initialize方法的调用时机和调用顺序如下图所示:

image

initialize方法的调用机制是通过objc_msgSend发送消息,所以调用流程也是遵循objc_msgSend

讲解示例Demo地址:https://github.com/guangqiang-liu/05-CategoryDemo

更多文章

上一篇 下一篇

猜你喜欢

热点阅读