OC中提供的category特性可以让我们动态的为现有类添加新的行为,以比继承更为简洁的方法来对Class进行扩展,无需创建对象类的子类就能为现有的类添加新方法,它可以为任何已经存在的Class添加方法,包括那些苹果没有公开源代码的类。
category作用
可以将类的实现分散到多个不同的文件或者不同的框架中,方便代码的管理,也可以对框架提供类的扩展
创建对私有方法的前向引用:
Cocoa没有任何真正的私有方法。只要知道对象支持的某个方法的名称,即使该对象所在的类的接口中没有该方法的声明,你也可以调用该方法。不过这么做编译器会报错,但是只要新建一个该类的类别,在类别.h文件中写上原始类该方法的声明,类别.m文件中什么也不写,就可以正常调用私有方法了。这就是传说中的私有方法前向引用。 所以说cocoa没有真正的私有方法。向对象添加非正式协议:
苹果官方文档:
An informal protocol is a category on NSObject, which implicitly makes almost all objects adopters of the protocol. (A category is a language feature that enables you to add methods to a class without subclassing it.) Implementation of the methods in an informal protocol is optional. Before invoking a method, the calling object checks to see whether the target object implements it. Until optional protocol methods were introduced in Objective-C 2.0, informal protocols were essential to the way Foundation and AppKit classes implemented delegation.
也就是说:非正式协议是NSObject类(显而易见,还包括它的子类)的类别,其所有的子类都含蓄地接受了这个协议。(类别是Objective-C的一个语言特点,可以让你在无需子类化的前提下为一个类增加方法。)非正式协议中的方法是否实现都是可选的,因此在调用非正式协议中的方法之前,需要去检查对象类是否实现了它。在Objective-C2.0中引入可选的正式协议方法之前,非正式协议是Foundation和AppKit类实现委托的唯一方式。所谓的非正式协议就是类别,即凡是NSObject或其子类的类别,都是非正式协议。
category与extension的区别:
- extension和category的创建方式一样,只要在原来选择Category的地方选择Extension即可。但是,extension只会生成 .h 文件。之后我们可以在.h中直接添加成员变量、属性和方法。而category是不能直接添加成员变量的(需要使用runtime添加)extension的常用形式不是创建一个单独的文件,而是在实现文件中添加私有的成员变量、属性和方法(比如创建Controller的时候XCode会自动生成)
- extension在编译期决议,它就是类的一部分,在编译期和头文件里的@interface以及实现文件里的@implement一起形成一个完整的类,它伴随类的产生而产生,亦随之一起消亡。extension一般用来隐藏类的私有信息,你必须有一个类的源码才能为一个类添加extension,所以你无法为系统的类比如NSString添加extension。
- 类别在运行期决议的,就类别和扩展的区别来看,我们可以推导出一个明显的事实,扩展可以添加实例变量,而类别是无法添加实例变量的(因为在运行期,对象的内存布局已经确定,如果添加实例变量就会破坏类的内部布局,这对编译型语言来说是灾难性的)。
category为什么不能添加实例变量但可以添加属性?
我们知道Objective-C类是由Class类型来表示的,它实际上是一个指向objc_class结构体的指针。所以类其实就是一个结构体,类别也是一样:
typedef struct category_t {
const char *name; // 类的名字(名称)
classref_t cls; // 类(CLS)
struct method_list_t *instanceMethods; // 类中所有给类添加的实例方法的列表
struct method_list_t *classMethods; // 类中所有添加的类方法的列表
struct protocol_list_t *protocols; // category实现的所有协议的列表
struct property_list_t *instanceProperties; // category中添加的所有属性
} category_t;
从类别的定义也可以看出类别的可以添加实例方法,类方法,甚至可以实现协议,添加属性和不可以添加实例变量。