【Objective-C】探索Category底层的实质
无论一个类设计的多么完美,在未来的需求演进中,都有可能会碰到一些无法预测的情况。那怎么扩展已有的类呢?一般而言,继承和组合是不错的选择。但是在Objective-C 2.0中,又提供了category这个语言特性,可以动态地为已有类添加新行为。如今category已经遍布于Objective-C代码的各个角落,从Apple官方的framework到各个开源框架,从功能繁复的大型APP到简单的应用,catagory无处不在。本文对category做了比较全面的整理,希望对读者有所裨益。
Objective-C中类别特性的作用如下:
(1)可以将类的实现分散到多个不同文件或多个不同框架中(补充新的方法)。
(2)可以创建私有方法的前向引用。
(3)可以向对象添加非正式协议。
Objective-C中类别特性的局限性如下:
(1)类别只能想原类中添加新的方法,且只能添加而不能删除或修改原方法,不能向原类中添加新的属性。
(2)类别向原类中添加的方法是全局有效的而且优先级最高,如果和原类的方法重名,那么会无条件覆盖掉原来的方法。
一、Category的底层实现
Objective-C 通过 Runtime 运行时来实现动态语言这个特性,所有的类和对象,在 Runtime 中都是用结构体来表示的,Category 在 Runtime 中是用结构体 category_t 来表示的,下面是结构体 category_t 具体表示:
typedef struct category_t {const char *name;//类的名字 主类名字classref_t cls;//类struct method_list_t *instanceMethods;//实例方法的列表struct method_list_t *classMethods;//类方法的列表struct protocol_list_t *protocols;//所有协议的列表struct property_list_t *instanceProperties;//添加的所有属性 } category_t;
从category的定义也可以看出category的可为(可以添加实例方法,类方法,甚至可以实现协议,添加属性)和不可为(无法添加实例变量)。
我们将结合 runtime 的源码探究下 Category 的实现原理。打开 runtime 源码工程,在文件 objc-runtime-new.mm
中找到以下函数:
void _read_images(header_info **hList, uint32_t hCount) {..._free_internal(resolvedFutureClasses);}// Discover categories. for (EACH_HEADER) {category_t **catlist =_getObjc2CategoryList(hi, &count);for (i = 0; i < count; i++) {category_t *cat = catlist[i];Class cls = remapClass(cat->cls);if (!cls) {// Category's target class is missing (probably weak-linked).// Disavow any knowledge of this category.catlist[i] = nil;if (PrintConnecting) {_objc_inform("CLASS: IGNORING category \?\?\?(%s) %p with ""missing weak-linked target class",cat->name, cat);}continue;}// Process this category. // First, register the category with its target class. // Then, rebuild the class's method lists (etc) if // the class is realized. BOOL classExists = NO;if (cat->instanceMethods || cat->protocols|| cat->instanceProperties){addUnattachedCategoryForClass(cat, cls, hi);if (cls->isRealized()) {remethodizeClass(cls);classExists = YES;}if (PrintConnecting) {_objc_inform("CLASS: found category -%s(%s) %s",cls->nameForLogging(), cat->name,classExists ? "on existing class" : "");}}if (cat->classMethods || cat->protocols/* || cat->classProperties */){addUnattachedCategoryForClass(cat, cls->ISA(), hi);if (cls->ISA()->isRealized()) {remethodizeClass(cls->ISA());}if (PrintConnecting) {_objc_inform("CLASS: found category +%s(%s)",cls->nameForLogging(), cat->name);}}}}// Category discovery MUST BE LAST to avoid potential races // when other threads call the new category code before // this thread finishes its fixups.// +load handled by prepare_load_methods() ... }
我们可以知道在这个函数中对 Category 做了如下处理:
(1)将 Category 和它的主类(或元类)注册到哈希表中;
(2)如果主类(或元类)已实现,那么重建它的方法列表;
Category的实现原理:
- 在编译时期,会将分类中实现的方法生成一个结构体 method_list_t 、将声明的属性生成一个结构体 property_list_t ,然后通过这些结构体生成一个结构体 category_t 。
- 然后将结构体 category_t 保存下来
- 在运行时期,Runtime 会拿到编译时期我们保存下来的结构体 category_t
- 然后将结构体 category_t 中的实例方法列表、协议列表、属性列表添加到主类中
- 将结构体 category_t 中的类方法列表、协议列表添加到主类的 metaClass 中
二、为何Category中的方法优先级高于原类中的方法?
// 这里大概就类似这样子插入 newproperties->next = cls->data()->properties; cls->data()->properties = newproperties;,
三、为何Category中不能添加实例变量?
通过结构体 category_t ,我们就可以知道,在 Category 中我们可以增加实例方法、类方法、协议、属性。这里没有 objc_ivar_list 结构体,代表我们不可以在分类中添加实例变量。
转载于:https://www.cnblogs.com/xjf125/p/11179570.html
【Objective-C】探索Category底层的实质相关推荐
- 【iOS开发】——Category底层原理、Extension、关联对象
[iOS开发]--Category底层原理.Extension.关联对象 Category是什么?它可以用来干什么? Category特点 Category的实质以及实现过程 Category结构体 ...
- Objective C 类别(Category)与类扩展(Extensions)
一.类别(Category) 类别(Category)是一种可以为现有的类(包括类簇:NSString...,甚至源码无法获得的类)添加新方法的方式无需从现有的类继承子类.类别添加的新方法可以被子类继 ...
- app启动页数秒加载 代码_iOS 底层探索 - 应用加载
一.前导知识 以下参考自 WWDC 2016 Optimizing App Startup Time : 1.1 Mach-O Mach-O is a bunch of file types for ...
- iOS底层探索二(OC 中 alloc 方法 初探)
前言 相关文章: iOS底层探索一(底层探索方法) iOS底层探索三(内存对齐与calloc分析) iOS底层探索四(isa初探-联合体,位域,内存优化) iOS底层探索五(isa与类的关系) iOS ...
- iOS 进阶之底层原理一OC对象原理alloc做了什么
人狠话不多,直接上干货.这是第一篇,之后还会持续更新,当作自己学习的笔记,也同时分享给大家,希望帮助更多人. 首先,我们来思考,下面这段代码的输出是否相同.答案很明显,p1.p2.p3是指向相同的对象 ...
- 探索式软件测试—Exploratory Software Testing
最近找到去年上半年看过一本关于测试方面书籍的总结笔记,一直放在我的个人U盘里,当时是用Xmind记录的,现在重新整理下分享给大家了! James A.Whittaker [美] 詹姆斯·惠特克(软件测 ...
- iOS之深入解析对象isa的底层原理
对象本质 一.NSObject 本质 OC代码的底层实现实质是 C/C++代码 ,继而编译成汇编代码,最终变成机器语言. ① clang C/C++ 编译器 Clang 是⼀个 C 语⾔.C++.Ob ...
- ios底层核心模板结构 - list_array_tt entsize_list_tt
探索objc底层原理过程中,经常会碰到一个模板 list_array_tt 你在类加载,方法查找,散列表,同步锁等等都会碰到这个结构,c++的模板功能十分强大,但代码看上去确实比较头疼 其实没那么糟了 ...
- 阿里二面:了解 MySQL 事务底层原理吗
你好,我是坤哥,今天是国庆最后一天,不知大家是否玩得尽兴,我基本在家带娃了,累得半死,顺带肝了一篇文,来自读者曾经在阿里的面试题,希望对大家有帮助,另外也欢迎大家加我微信「geekoftaste」,一 ...
最新文章
- 面试鹅厂,我三面被虐的体无完肤。。。
- 1669 DINIC+二分
- Nginx 配置 SSL 证书步骤小记
- js 获取 本周、上周、本月、上月、本季度、上季度的开始结束日期
- s5pv210——中断系统相关介绍
- rpm安装mysql5.6.37_MySQL之—RPM方式安装MySQL5.6 代码实例详解
- 表头样式_1分钟学会制作Word两栏、三栏表头
- hdu 4417 树状数组查询区间不是1到n时需要转换,例[0,5]变成[1,6]
- 拓端tecdat|R语言生存分析可视化分析
- sqlmap重要参数详解+用法,解决入门难题
- EPSON爱普生系列打印机清洗更换墨盒方法
- 福昕阅读器中删除单个,多个注释,隐藏所有注释。
- cr2格式是什么意思?cr2格式用什么软件打开?cr2格式怎么转换成jpg
- 推荐一款使用快捷的免费文字识别OCR(图片转文字)在线服务
- Android应用在新浪微博授权提示:文件不存在 C8998 的解决方法
- LeetCode 2171. 拿出最少数目的魔法豆
- 关于LSB图片隐写的解法
- pin ——pin tool代码注释 各pin tool的用途
- (个人学习笔记)利用ensight进行EDEM耦合FLUENT后处理
- socket是一个编程接口
热门文章
- php date( ymd_PHP DATE()
- python水印倾斜_python中图像特定位置的水印算法
- 写代码用什么笔记本_1—2千预算,编程、写代码、办公、PS修图笔记本推荐/选购指南...
- Dataframe 新增一列, apply 通用方法
- React 16 Jest ES6 Class Mocks(使用ES6语法类的模拟) 实例三、四
- 空间复杂度,实现从excel导出到txt文件中的java代码自动构建,逻辑条件不同实现则不同...
- JVM可生成的最大Thread数量探索
- iOS调试技巧-断点调试
- Centos7 把php5.4升级到php5.6
- pycharm error:no module named caffe