Category源码分析

一,首先为啥要使用分类?

  • 开发中分类可以吧不同的功能分散到多个不同的文件及框架,减少单个文件的体积,方便管理
  • 创建私有方法

二,Category在编译时刻,都是独立的,各自生成各自的文件

XZPerson

#import <Foundation/Foundation.h>

@interface XZPerson : NSObject

@end
#import "XZPerson.h"

@implementation XZPerson

@end

 XZPerson的分类

#import "XZPerson.h"

@interface XZPerson (Eat)
- (void)eat;
@end
#import "XZPerson+Eat.h"

@implementation XZPerson (Eat)

- (void)eat{
    NSLog(@"eat");
}
+ (void)run{
    NSLog(@"run");
}

@end

使用xcrun -sdk iphoneos clang  -arch arm64 -rewrite-objc  查看分类(分析的是编译时刻生成的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;
};

static struct _category_t _OBJC_$_CATEGORY_XZPerson_$_Eat __attribute__ ((used, section ("__DATA,__objc_const"))) = 
{
	"XZPerson",
	0, // &OBJC_CLASS_$_XZPerson,
	(const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_XZPerson_$_Eat,
	(const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_XZPerson_$_Eat,
	0,
	0,
};

其中 _OBJC_$_CATEGORY_INSTANCE_METHODS_XZPerson_$_Eat对应的
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_XZPerson_$_Eat __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	sizeof(_objc_method),
	1,
	{{(struct objc_selector *)"eat", "v16@0:8", (void *)_I_XZPerson_Eat_eat}}
};里面存放了对象方法



其中_OBJC_$_CATEGORY_CLASS_METHODS_XZPerson_$_Eat 对应的
static struct /*_method_list_t*/ {
	unsigned int entsize;  // sizeof(struct _objc_method)
	unsigned int method_count;
	struct _objc_method method_list[1];
} _OBJC_$_CATEGORY_CLASS_METHODS_XZPerson_$_Eat __attribute__ ((used, section ("__DATA,__objc_const"))) = {
	sizeof(_objc_method),
	1,
	{{(struct objc_selector *)"run", "v16@0:8", (void *)_C_XZPerson_Eat_run}}
};里面存放了类方法

 综上可知分类的对象方法最终也会到类对象的对象方法列表中,类方法也会到元类的类方法列表中。

下面我们来分析下是如何做到的?

1.这个要去研究下runtime的源码,通过Runtime加载某个类的所有Category数据

源码解读顺序objc-os.mm~_objc_init~map_images(镜像)map_images_nolockobjc-runtime-new.mm_read_images

remethodizeClass(重新方法化)attachCategories(方法附加)attachListsreallocmemmove memcpy

memcpy是从内存左侧一个字节一个字节的复制拷贝

memmove是将需要拷贝的内容一次性移动拷贝。

2. 把所有Category的方法、属性、协议数据,合并到一个大数组中

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

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

 

所以:分类+类中如果含有相同的方法,会优先调用分类中的方法,假如两个分类(针对同一个类的不同分类)含有相同的方法,调用顺序跟编译的顺序有关,根据前面的结论会直接优先调用最后参与编译的分类。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值