面试题答案
一键面试Objective-C类别(Category)实现原理及runtime层面工作机制
- 实现原理
- Category是在运行时(runtime)将新的方法、属性、协议等添加到已有的类中。它通过运行时的动态加载机制,在运行时将Category的信息合并到类的分发表(method list)等相关数据结构中。
- 一个Category主要由
category_t
结构体表示,其包含了指向类的指针、Category的名称、实例方法列表、类方法列表、属性列表和协议列表等信息。 - 在编译时,Category会生成对应的目标文件(.o),在链接阶段,这些目标文件会被链接到可执行文件中。运行时,runtime会根据加载的类,将相关的Category信息合并到类的数据结构中。
- runtime层面工作机制
- 当程序启动,runtime会加载类和其相关的Category。runtime首先会处理类的加载,然后遍历该类所有相关的Category。
- 对于Category中的实例方法,runtime会将其添加到类的实例方法列表中。在查找方法时,runtime会优先在Category添加的方法列表中查找,如果找到了就直接调用,这也是Category方法可以覆盖类原有方法的原因(因为先查找到Category的方法)。
- 对于类方法,runtime会将Category中的类方法添加到元类(meta - class)的方法列表中。同样,在查找类方法时,会先在元类的方法列表中查找,优先查找Category添加的类方法。
与Class Extension对比
- Class Extension特点
- 定义位置:Class Extension(类扩展)通常定义在.m文件中,且必须与类的实现关联。它本质上是类的一部分,只是对类的接口进行了补充。
- 方法和属性:可以添加实例变量(但在运行时通过关联对象实现,不能直接访问)、实例方法和属性。与Category不同,Class Extension中声明的方法必须在类的实现中实现。
- 作用域:其作用域只在定义的.m文件内有效,对外不可见。
- Category特点
- 定义位置:可以在任何地方定义,只要在类被定义之后即可,并且可以有多个Category定义在不同的文件中。
- 方法和属性:主要用于添加方法,虽然可以通过关联对象添加属性,但不能直接声明实例变量。
- 作用域:全局可见,只要导入包含Category定义的头文件,就可以使用Category中的方法。
- 优缺点及适用场景
- Class Extension优点:对类的内部实现进行扩展,增加的方法和属性对外部不可见,保证了类的接口整洁,适用于类内部的私有方法和属性扩展。例如,在一个复杂的ViewController类中,使用Class Extension添加一些只在本类内部使用的私有方法,方便代码组织。
- Class Extension缺点:增加的方法必须在类的实现中实现,灵活性相对较差。
- Category优点:可以在不修改类的源代码的情况下,为类添加新方法,提高了代码的复用性和可维护性。比如为系统类(如NSString)添加自定义的扩展方法。
- Category缺点:如果多个Category添加了同名方法,调用顺序依赖于编译和链接顺序,可能导致难以预料的行为。且不能直接声明实例变量。
与Protocol对比
- Protocol特点
- 定义:Protocol是一种特殊的接口,它只定义方法列表,不包含方法的实现。任何类都可以遵循一个或多个Protocol,并根据需要实现Protocol中定义的方法。
- 方法类型:Protocol中的方法可以分为必须实现和可选实现的方法。
- 作用:用于实现类似于多重继承的功能,使不同的类可以遵循相同的Protocol,实现特定的行为。
- Category特点
- 定义:为已有的类添加新的方法、属性等具体实现。
- 方法类型:添加的方法都有具体实现,并且会修改类的行为。
- 优缺点及适用场景
- Protocol优点:实现了一种松散的耦合关系,不同的类可以遵循同一个Protocol,实现特定的功能,提高了代码的可扩展性和复用性。例如,在一个社交应用中,不同的用户界面类可以遵循同一个“可分享”Protocol,实现分享功能。
- Protocol缺点:Protocol只定义方法接口,不提供实现,需要遵循的类自己实现,对于一些通用功能实现不够便捷。
- Category优点:可以直接为类添加具体实现,方便快捷,特别是对于一些系统类的功能扩展。
- Category缺点:只能为已有的类添加方法,不能像Protocol那样用于多个不同类的统一行为抽象。