Category本质
Category的使用场合是什么?
Category的实现原理?
Category和Extension的区别是什么?
Category中有load方法吗?load方法是什么时候调用的?
load方法能继承吗?
load、initialize方法的区别是什么?它们在category中的
调用的顺序?以及出现继承时他们之间的调用过程?
Category能否添加成员变量?如果可以,如何给Category添加成员变量?
创建一个Person类,创建Person的Eat分类,Person的Test分类。
@interface Person : NSObject - (void)run; @end @implementation Person - (void)eat { NSLog(@"eat"); } @end复制代码
@interface Person (Eat) <NSCopying, NSCoding> - (void)eat; @property (assign, nonatomic) int weight; @property (assign, nonatomic) double height; @end @implementation Person (Eat) - (void)eat { NSLog(@"eat"); } @end复制代码
@interface Person (Test) - (void)test; @end @implementation Person (Test) - (void)test { NSLog(@"test"); } @end复制代码
Person *person = [[Person alloc] init]; [person run]; [person test]; [person eat];复制代码
我们所说的调用方法,就是发送消息。
person 调用run方法,就是
objc_msgSend(person, @selector(run));
前边我们说过isa及对象实例方法在类对象中。可以很清楚的知道run方法,在person对象的类对象的方法列表中。。。
那 test方法 eat方法是分类中的方法 , 它们存到什么地方了呢?
难道分类也有类对象????我们分类的对象方法,放在对应的分类类对象里吗?
答案是不存在的。 一个类永远只有一个类对象。不存在分类类对象。
那 test方法 eat方法 最终存放在什么哪里呢?
那到底放在那里呢??????
其实,最终程序运行起来之后,run方法 test方法 eat方法,1个分类也好100个分类也好,最终都会合并到
一个类对象中。存在到类对象的方法列表中。。。。也就是Person类对象的方法列表里。。。。。。
不论你调用那个方法,最终都是通过instance对象的isa到类对象中寻找,然后调用的。。。。。。这是一个结论,稍后证明。
那么分类中的类方法存在在什么地方呢?同样,不管一个分类也好,100个分类也好,其中的类方法,最终都会合并到一个元类对象中,存到元类的类对象的方法列表中。这是结论,稍后证明。
那什么时候合并分类中的方法到类中呢?在编译的时候?还是在运行的时候呢?
是在运行的时候,会用到runtime,在程序运行过程中合并的。
接下来==========
我们看看编译后的分类的本质是什么?
找到Person+Test.m所在的文件夹。
在终端敲入如下指令:xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Person+Test.m
查看生成的Person+Test.cpp文件
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; // 分类中的 属性列表(分类中的属性只是一个 方法声明,没有方法实现。也不生成成员变量) };复制代码
找到 分类编译完毕后 的 底层结构体。
程序没运行之前,你的分类方法是存在在这个分类的结构体中。
当程序运行时,利用runtime把分类结构体中的方法列表中的方法,合并到类对象的方法列表中。
我们再找到这个编译后的代码:
static struct _category_t _OBJC_$_CATEGORY_Person_$_Test __attribute__ ((used, section ("__DATA,__objc_const"))) = { "Person", 0, // &OBJC_CLASS_$_Person, (const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_Test, (const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_Person_$_Test, 0, 0, };复制代码
再给分类结构体赋值。
我们看到给分类的 五个域赋值。
我们看第三个域 (const struct _method_list_t *)&OBJC_CATEGORY_INSTANCE_METHODS_Person__Test,是什么东东???
我们找的编译后的源代码是这样的:
static struct /*_method_list_t*/ { unsigned int entsize; // sizeof(struct _objc_method) unsigned int method_count; struct _objc_method method_list[1]; } _OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_Test __attribute__ ((used, section ("__DATA,__objc_const"))) = { sizeof(_objc_method), 1, {{(struct objc_selector *)"test", "v16@0:8", (void *)_I_Person_Test_test}} };复制代码
有没有看到一个"test" ,没错,这正是我们的test方法。
作者:用户2109385917629
链接:https://juejin.cn/post/7021404530302517255