Category底层原理实现
本文首发于公众号【程序员华仔】
今天一起来探究下Category的底层实现原理。
1.Category 简介
Category是Object-C 2.0之后新增加的特性功能,主要用于对已存在类增加方法、协议和属性。在实际项目中,我们主要用它来扩展类的功能,实现类的多继承等事情。
2. Category 源码初探
要对Category的源码进行研究,首先我们建个实际的类,通过实际类的分析来看Category的内部情况。
这里先新建个Person类,
实现Person+PersonTest的类目。
@interface Person (PersonTest) {
}
@property(nonatomic,strong)NSString *name;
+ (void)loadAllData;
- (void)saveAllData;
@end
@implementation Person (PersonTest)
+ (void)loadAllData {
}
- (void)saveAllData {
}
@end
以上Person类,新增加了类方法,对象方法和属性。我们来看看转换成C++代码之后,内部什么情况?
使用clang命令把上面的OC代码转换成C++代码。具体为:进入Person+PersonTest.m 文件下,在终端执行一下命令:
clang -rewrite-objc Person+PersonTest.m -o tPerson.cpp
看过我之前写过的文章的同学就知道,其实还有一个命令,可以把Object-C转成C++代码。如下命令:
xcrun -sdk iphoneos clang -archarm64 -rewrite-objc Person+PersonTest.m -o tPerson.cpp
其实两个命令,后面部分一模一样,只是后一个命令,使用了xcrun。
通过查看cpp文件,我们可以知道以下情况:
1.类方法和对象方法,都对应_method_list_t的结构体。
2.属性,对应为_prop_list_t的结构体。
3.协议,对应为_protocol_list_t的结构体(cpp文件中未体现,查资料而得)。
4.有一个_category_t结构,里面有对应类方法,对象方法,协议和属性的成员变量,存储着Person类的Category信息。
具体如下的信息:
1.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_$_PersonTest __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"saveAllData", "v16@0:8", (void *)_I_Person_PersonTest_saveAllData}}
};
2.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_Person_$_PersonTest __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_objc_method),
1,
{{(struct objc_selector *)"loadAllData", "v16@0:8", (void *)_C_Person_PersonTest_loadAllData}}
};
3.static struct /*_prop_list_t*/ {
unsigned int entsize; // sizeof(struct _prop_t)
unsigned int count_of_properties;
struct _prop_t prop_list[1];
} _OBJC_$_PROP_LIST_Person_$_PersonTest __attribute__ ((used, section ("__DATA,__objc_const"))) = {
sizeof(_prop_t),
1,
{{"name","T@\"NSString\",&,N"}}
};
4.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;
};
3. Category 底层源码
了解了_category_t结构体之后,我们看下Category底层源码。
Category底层源码是由苹果公司开发并已经对外开源了,我们可以在苹果开源网站上获取,具体代码在objc4库上。
具体下载objc4库的方式,如下图(这里我获取最新的库版本为objc4-841.13)
下载好objc4库之后,_category_t结构体代码主要在objc-runtime-new(.h.m)文件厘米。如下图
通过这段代码,告诉我们了category的结构信息如下:
1.name 为名称
2.cls 为类
3. instanceMethods为对象方法,且是一个列表(包含该category所有新增加的方法)。
4. classMethods为类方法,同instanceMethods一样也是列表。
5.protocols为协议列表
6. instanceProperties为实例属性列表
7. _classProperties为类属性列表。
由此我们可知在category中可以添加对象方法、类方法、协议实现、属性。
这里有个面试题:
问:Category为什么只能加方法不能加属性?
答:分类的实现原理是将category中的类方法、对象方法、属性、协议数据放在category_t结构体中,然后将结构体内的方法列表拷贝到类对象的方法列表。
Category可以添加属性,但是并不会自动生成成员变量及set/get方法。因为category_t结构体中并不存在成员变量。通过之前对对象的分析我们知道成员变量是存放在实例对象中的,并且编译的那一刻就已经决定好了。而分类是在运行时才去加载的。那么我们就无法再程序运行时将分类的成员变量中添加到实例对象的结构体中。因此分类中不可以添加成员变量。
了解了Category的底层实现,我们来了解下Category的加载过程。
4.category的加载
我们都知道Objective-C的运行依赖于runtime,在OC运行时,runtime的入口如下。
在这段入口代码中,_dyld_objc_notify_register函数才是OC初始化的开始。
category加载到类中是在map_images的时候发生的,而map_images最终会调用到objc-runtime-new.mm中的_read_images方法。
在_read_images函数中,主要做以下事情:
1.通过_getObjc2CategoryList函数获取到category的列表。
2.将category中的对象方法,协议以及属性添加到类中。
3.将category中的类方法、协议以及类属性添加到类的元类中。
然后会调用remethodizeClass方法,再调用attachCategories。在attachCategories函数中,将category中的对象方法、属性、协议添加到了类中。最后会将这些信息添加到类的data中,这样就实现了Category类与类中的元类的联系。
5.Categroy方法先后调用问题。
在实际开发过程中,如果在category定义了和类中一样的方法,这时候在方法调用的时候,调用的是category中的方法还是类中的方法呢?
通过阅读attachLists函数,我们知道了:在category中的方法加载到类的时候,其方法会优先添加到类方法列表的前面,并未替换原有的方法。而方法的调用是顺序查找的,所以会先调用category中的方法。
Category底层原理实现相关推荐
- 【iOS开发】——Category底层原理、Extension、关联对象
[iOS开发]--Category底层原理.Extension.关联对象 Category是什么?它可以用来干什么? Category特点 Category的实质以及实现过程 Category结构体 ...
- 网络协议从入门到底层原理(11)网络爬虫、无线网络、HTTP缓存、即时通信、流媒体
补充知识 网络爬虫 网络爬虫的简易实例 robots.txt 无线网络 HTTP 缓存(Cache) 缓存 - 响应头 缓存 - 请求头 缓存的使用流程 即时通信(IM) XMPP MQTT 流媒体 ...
- 揭密 Java方法调用的底层原理
关注公众号"java后端技术全栈" 回复"000"获取优质面试资料 大家好,我是老田,今天来和大家聊聊Java方法调用的底层原理. 我们在日常开发中,其实很少去 ...
- 没有与参数列表匹配的 重载函数 getline 实例_面试题:方法重载的底层原理?...
前语:微信改版后,大量读者还没养成点赞的习惯,如写得好,望大家阅读后在右下边"好看"处点个赞,以示鼓励!长期坚持原创真的很不容易,多次想放弃,坚持是一种信仰,专注是一种态度. 关于 ...
- synchronized底层原理_你用过synchronized吗?它的底层原理是什么?Java经典面试题来了...
并发编程已经成为程序员必备技能 作为Java程序员,不懂得并发编程显然已经不能满足市场需求了,尤其是在面试过程中将处于被动地位,也有可能面试将就此终结. 那么作为Java开发者的你,日常虽然可以基于J ...
- iOS底层原理 - 常驻线程
iOS底层原理 - 常驻线程 在 AFN 2.0 时代,会经常看到 AFN 创建一个常驻线程的方式: 0️⃣ AFN 2.0 时代的常驻线程 + (NSThread *)networkRequestT ...
- elasticsearch原理_ElasticSearch读写底层原理及性能调优
ES写入/查询底层原理 1. Elasticsearch写入数据流程 客户端随机选择一个ES集群中的节点,发送POST/PUT请求,被选择的节点为协调节点(coordinating node) 协调节 ...
- 嘿嘿,我就知道面试官接下来要问我 ConcurrentHashMap 底层原理了,看我怎么秀他...
来自:烟雨星空 前言 上篇文章介绍了 HashMap 源码后,在博客平台广受好评,让本来己经不打算更新这个系列的我,仿佛被打了一顿鸡血.真的,被读者认可的感觉,就是这么奇妙. 原文:面试官再问你 Ha ...
- 面试官再问你 HashMap 底层原理,就把这篇文章甩给他看
来自:烟雨星空 前言 HashMap 源码和底层原理在现在面试中是必问的.因此,我们非常有必要搞清楚它的底层实现和思想,才能在面试中对答如流,跟面试官大战三百回合.文章较长,介绍了很多原理性的问题,希 ...
- 为了把mysql的索引底层原理讲清楚,我把计算机翻了个底朝天
来自:非科班的科班 什么是索引 概念:索引是提高mysql查询效率的数据结构.总的一句话概括就是索引是一种数据结构. 数据库查询是数据库的最主要功能之一.设计者们都希望查询数据的速度能尽可能的快,因此 ...
最新文章
- XML和JSON数据格式对比
- java 基础算法教程ppt,基础排序算法(附加java实现)
- 程序员别只顾着敲代码了,看看吧
- R语言泊松回归(poisson)模型案例:基于robust包的Breslow癫痫数据集
- Linux入门!Linux无法联网解决办法!CentOS7、VMPlayer、VMWareWorkstation16资源!VMWareWorkstation16序列号!VMware安装Centos7!
- C# 关闭正在执行的文件
- 一家美资企业的java servlet面试题
- bzoj2007: [Noi2010]海拔
- How to download BOM from ERP to CRM
- 从Linux基础到k8s进阶,马哥_K8s进阶实战(11)Kubernetes系统扩展
- 机器学习_一条会说666的咸鱼
- springmvc配置中文乱码过滤器
- PHP配置问题(找不到指定模块)解决办法
- 同步现象 心理学_「心理学学了些什么?」基础心理学知识1
- 域中计算机改名,找不到网络路径,电脑加域失败提示”找不到网络路径”的解决办法...
- java充值卡号生成_java实现点卡生成
- JAVA最佳学习方法
- php json输出对象的属性值,JavaScript_jquery动态遍历Json对象的属性和值的方法,1、遍历 json 对象的属性/ - phpStudy...
- 提示网站服务器403,如何解决电脑网页提示网站拒绝显示此网页和HTTP 403的问题...
- 科普直播,或将成为金融企业引流获客的渠道
热门文章
- 学计算机基础知识的app,电脑基础知识零基础入门版-电脑基础知识APP手机大全v1.0 安卓版-007游戏网...
- java在上海就业_叩丁狼教育上海Java一期就业报道
- 广告代码(弹窗和富媒体)
- 云原生的年代service mesh不止Istio,还有另一个选择-Kuma
- Mac显示桌面的快捷方式
- 顶峰Android手机视频转换器,顶峰FLV视频转换器
- diy高性能存储服务器,存储服务器 diy
- 新在线一键制作表白网系统源码
- 云操作系统,是真的吗?(译文)
- 扫描技术的原理与应用(Nmap使用)