iOS中Category的底层实现原理

1. Category的使用场景

Category也叫分类类别,是OC提供的一种扩展类的方式。不管是自定义的类还是系统的类,我们都可以通过Category给原有类扩展方法(实例方法和类方法都可以),而且扩展的方法和原有的方法的调用方式是一模一样的。比如我项目中经常需要统计一个字符串中字母的个数,但是系统没有提供这个方法,那我们就可以用CategoryNSString类扩展一个方法,然后只需引入Category的头文件就可以和调用系统方法一样来调用扩展的方法。

// 给NSString类添加一个Category,并扩展一个实例方法
@interface NSString (QJAdd)

- (NSInteger)letterCount;

@end
// 在需要使用这个扩展方法的地方引入头文件 #import "NSString+QJAdd.h",然后就可以调用这个扩展方法了
- (void)test{
    NSString *testStr = @"sdfjshdfjk.,d.889";
    NSInteger letterCount = [testStr letterCount];
}

Category除了用来给类进行扩展外,还有一种比较高级的用法,就是用来拆分模块,将一个大的模块拆分成多个小的模块,方便进行维护和管理。什么意思呢?我就举一个很多开发人员都会存在的问题,就是AppDelegate这个类。这个类是刚创建项目时自动生成的,用来管理程序生命周期的。在刚创建项目时,这个类中是没有多少代码的,但是随着项目的进行,越来越多的代码会被放在这个类里面。比如说集成极光推送、友盟、百度地图、微信SDK等各种第三方框架时,这些第三方框架的初始化工作,甚至是相关的业务逻辑代码都会放在这个类里面,这就导致随着APP的功能越来越复杂,AppDelegate中的代码就会越来越多,有的甚至有几千行,看着就让人头皮发麻。

这时我们就可以利用Category来对AppDelegate进行拆分,首先我们就需要对AppDelegate中的代码进行划分,把同一种功能的代码抽取出来放在一个分类里面。比如说我可以新建一个极光推送的分类,然后把所有和极光推送有关的代码都抽出来放入这个分类,把所有和微信相关的代码抽出来放进微信的分类中,后面又有新的功要添加的话我只需要新建分类就好了。维护的时候要改什么功能的代码就直接找相应的分类就好了。

// 把所有和极光推送有关的代码都抽出来放入这个分类
#import "AppDelegate.h"

@interface AppDelegate (JPush)

@end

 

2. Category的底层实现

在讲解这个问题之前,我们需要对OC方法调用的底层机制以及类对象的内存存储结构有一定了解,对于这一块不熟悉的可以先去看看我的另外一篇博客OC对象的本质

我们先来思考这样一个问题,当我们通过Category给一个类扩展了一个实例方法,我们调用这个实例方法时,它也是通过实例的isa指针找到类对象,然后在类对象的方法列表中去查找这个方法。那么Category扩展的方法是如何被添加到类对象的方法列表中去的呢?是编译的时候添加进去的还是运行的时候添加进去的呢?

首先我们来看下Category的内存存储结构,Category底层其实就是一个category_t类型的结构体,我们可以在objc4源码的objc-runtime-new.h文件中看到它的定义:

// 定义在objc-runtime-new.h文件中
struct category_t {
    const char *name; // 比如给Student添加分类,name就是Student的类名
    classref_t cls;
    struct method_list_t *instanceMethods; // 分类的实例方法列表
    struct method_list_t *classMethods; // 分类的类方法列表
    struct protocol_list_t *protocols; // 分类的协议列表
    struct property_list_t *instanceProperties; // 分类的实例属性列表
    struct property_list_t *_classProperties; // 分类的类属性列表
};

从这个结构体可以看出,Category中存储的不仅有方法列表,还有协议列表和属性列表。

我们每创建一个分类,在编译时都会生成这样一个结构体并将分类的方法列表等信息存入这个结构体。在编译阶段分类的相关信息和本类的相关信息是分开的。等到运行阶段,会通过runtime加载某个类的所有Category数据,把所有Category的方法、属性、协议数据分别合并到一个数组中,然后再将分类合并后的数据插入到本类的数据的前面。

想要了解详细的流程,可以去看源码</

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值