iOS的Category

先来看一下分类的本质是什么, 还是老方法, 将分类编译成C++文件.

首先, 新建一个Person的分类:

image.png

具体实现如下:
Person.h

#import "Person.h"

NS_ASSUME_NONNULL_BEGIN

@protocol DrinkProtocol <NSObject>

- (void)drink;

@end

@interface Person (Eat)
@property (nonatomic, strong) NSString *name;
@end

NS_ASSUME_NONNULL_END

Person.m

#import "Person+Eat.h"

@implementation Person (Eat)

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

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

@end

我在分类里面, 有协议, 有属性, 有方法, 那么我们将它编译成C++文件, 看看是什么样的.
C++文件里, 搜索_category_t, 发现:

static struct _category_t _OBJC_$_CATEGORY_Person_$_Eat __attribute__ ((used, section ("__DATA,__objc_const"))) = 
{
    "Person",
    0, // &OBJC_CLASS_$_Person,
    (const struct _method_list_t *)&_OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_Eat,
    (const struct _method_list_t *)&_OBJC_$_CATEGORY_CLASS_METHODS_Person_$_Eat,
    0,
    (const struct _prop_list_t *)&_OBJC_$_PROP_LIST_Person_$_Eat,
};

这是结构体的赋值情况
那这个结构体的定义是什么呢?

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;
};

上下对比就可以发现
赋值情况是: 将Person赋值给name, cls0, 然后实例方法着重说一下, 它是将_OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_Eat这样一个结构体的地址赋值给instance_methods
_OBJC_$_CATEGORY_INSTANCE_METHODS_Person_$_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_Person_$_Eat __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_objc_method),
    1,
    {{(struct objc_selector *)"eat", "v16@0:8", (void *)_I_Person_Eat_eat}}
};

这个结构体的定义是

struct _method_list_t {
    unsigned int entsize;  // sizeof(struct _objc_method)
    unsigned int method_count;
    struct _objc_method method_list[1];
}

第一个成员变量是entsize, 是struct _objc_method这个结构体的大小.

struct _objc_method {
    struct objc_selector * _cmd; // SEL (一般是方法名(struct objc_selector *)"eat", 将"eat"的`char*`强转成`struct objc_selector *`)
    const char *method_type; // 方法类型
    void  *_imp; // 实现的指针
};

第二个成员变量是method_count, 方法数量, 在这个例子里, 方法数量是1;
第三个成员变量是struct _objc_method类型的结构体数组. 这个结构体数组里面存的是每一个方法结构体, 方法结构体存的是方法名, 方法类型, 和方法实现(指针)

然后类方法是将_OBJC_$_CATEGORY_CLASS_METHODS_Person_$_Eat这样一个结构体地址赋值给class_methods, 这个和instance_methods是差不多的.

protocols0,
properties_OBJC_$_PROP_LIST_Person_$_Eat这样一个结构体的地址, 我们来看看这个结构体

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_$_Eat __attribute__ ((used, section ("__DATA,__objc_const"))) = {
    sizeof(_prop_t),
    1,
    {{"name","T@\"NSString\",&,N"}}
};

这个和方法结构体很像:

struct _prop_list_t {
    unsigned int entsize;  // sizeof(struct _prop_t)
    unsigned int count_of_properties;
    struct _prop_t prop_list[1];
}
struct _prop_t {
    const char *name; // 属性名称
    const char *attributes; // 属性的特征(类型等)
};
{
  "name",
  "T@\"NSString\",&,N"
}

从上面可以看出, 分类的本质就是一个个的struct _category_t结构体.创建一个分类, 就会在内存中生成一个struct _category_t结构体. 在编译阶段就是如此

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

推荐阅读更多精彩内容

  • Category基本使用 分类和类一样都是在接口内声明,在类文件内实现。但是分类不可声明实例变量,只可声明属性和方...
    QiShare阅读 352评论 0 1
  • Category在平时的工作中也是经常用到,是开发中不可缺少的一个利器,简单介绍。 优点: 不需要通过增加子类而增...
    木子雨廷t阅读 1,020评论 1 11
  • Category 主要的功能是给现有的类增加新的方法,Category 的优点是: 可以“分解”庞大的逻辑,进行业...
    valentizx阅读 459评论 0 1
  • 一、Category的实现原理 我们先看一个简单Demo创建Person类以及它的两个分类Person+Test、...
    maskerII阅读 224评论 0 0
  • 一 ,category简介 本文是自我学习iOSruntime的过程中学习的Category的一个自我学习和总结的...
    携YOU手同行阅读 386评论 0 2