OC分类(category)和扩展(extension)

首先,分别来说下分类(category)和扩展(extension)的用处。然后来解读一下分类的底层实现

分类常见的应用
1、可以将臃肿的类根据不同业务划分为多个模块,方便进行管理
2、对原有的类进行扩展,给类添加方法。特别是给系统自带的类方法

分类的注意点
1、分类里面可以定义@property属性,但是不会自动生成set和get方法,以及对应的成员变量
2、分类不能添加成员变量,但是可以通过关联对象的方式添加成员变量
3、分类中有和原有类同名的方法, 会优先调用分类中的方法
4、多个分类中同名方法,优先调用后面参与编译的分类里面的方法

扩展的应用
1、为一个类声明一些额外的方法和属性
2、常用在.m文件中添加一些私有属性。创建viewcontroller文件时会自动在.m文件内最上面实现扩展代码

扩展注意点
1、扩展只能声明方法、属性,具体实现需要在源文件中实现

分类的底层结构

struct category_t {
    const char *name;
    classref_t cls;
    WrappedPtr<method_list_t, PtrauthStrip> instanceMethods;
    WrappedPtr<method_list_t, PtrauthStrip> classMethods;
    struct protocol_list_t *protocols;
    struct property_list_t *instanceProperties;
    // Fields below this point are not always present on disk.
    struct property_list_t *_classProperties;

    method_list_t *methodsForMeta(bool isMeta) {
        if (isMeta) return classMethods;
        else return instanceMethods;
    }

    property_list_t *propertiesForMeta(bool isMeta, struct header_info *hi);
    
    protocol_list_t *protocolsForMeta(bool isMeta) {
        if (isMeta) return nullptr;
        else return protocols;
    }
};

分类的加载过程
1、通过Runtime加载某个类的所有Category数据
2、把所有Category的方法、属性、协议数据,合并到一个大数组中。后面参与编译的Category数据,会在数组的前面
3、将合并后的分类数据(方法、属性、协议),插入到类原来数据的前面

源码调用顺序
1、_objc_init
2、map_images
3、map_images_nolock
4、_read_images
5、remethodizeClass
6、attachCategories
7、attachLists
8、realloc、memmove、 memcpy

通过分析就知道为什么分类不能添加成员变量,分类同名方法调用顺序

扩展
网上分类文章很多,但是关于扩展的文章较少,而且还都有错误,扩展的底层源码没法分析,下面就来验证一下网上关于扩展的说法

1、不能给系统类添加扩展,关于这个说法尝试一下几步
创建一个iOS工程,给NSObject添加一个扩展NSObject+Extension,编译没问题,运行没问题,所以可以添加扩展文件
在扩展文件中添加属性objName,编译没问题,运行没问题
在控制器中导入扩展的头文件,创建NSObject对象obj,给对象obj.objName赋值,编译没问题,运行报错unrecognized selector sent to instance 0x6000037b4630。找不到对应的方法
创建NSObject分类NSObject+Category,在分类.m文件中导入NSObject+Extension,在分类中使用属性objName。编译没问题,运行报错
在NSObject+Extension中添加方法声明,在分类中实现方法,在控制器中调用方法,编译没问题,运行没问题

总结如下,可以给系统类添加Extension,但是扩展中添加的方法和属性没有意义。
可以再扩展中添加方法声明,在分类中添加具体的方法实现。
在系统类扩展中声明的属性,不会自动生成set方法和get方法。可以再扩展中声明,在分类中添加关联对象。
由此可见,扩展就相当于对类.h的扩展,由于系统类.m文件拿不到,所以对系统类的扩展没有意义,还需要结合分类使用,反而要多导入一个头文件

2、类扩展中声明的方法没被实现,编译器会报警,但是分类中的方法没被实现编译器是不会有任何警告的
这个说法还是不对的
尝试了一下,结果是
扩展中声明的方法没有实现,会在原来的类里面警告
分类中明的方法没有实现,会在分类里面警告

3、非系统类扩展,只有把扩展头文件导入到原类的.m文件中会自动生成set和get方法。扩展声明的方法需要在分类或者元类的.m文件内实现

通过对扩展的分析,又拓展了一个扩展的应用场景,三方库对系统类添加的分类中如果有私有的方法,正常情况是没办法调用的,但是我们可以给这个系统类添加一个拓展,将私有方法在扩展中声明一下就可以调用了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,036评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,046评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,411评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,622评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,661评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,521评论 1 304
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,288评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,200评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,644评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,837评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,953评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,673评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,281评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,889评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,011评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,119评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,901评论 2 355

推荐阅读更多精彩内容