http://www.cocoachina.com/bbs/read.php?tid=168739#建议 194: 区别清楚类继承、类别和类扩展
在向对象编程特性方面,Objective-C提供子类和类别等两个非常重要的部分。子类应该反复被各种编程书籍介绍过。它是面向对象编程继承特性的关键语法,它给类添加了延续并且多样化自己的方法。可以说没有继承就没有面向对象编程这玩意。而类别相对于子类就不那么出名了。其实 类别思想出世于 smalltalk,所以它不能算是一个新生事物。
先说一下这2个特性最主要的区别。简单可以这么理解,子类体现了类的上下级关系,而 category 是类间的平级关系,图1-63展示了二者区别。
图1-63 子类和类别对比
如上图所示,左侧是子类,可以看到class、subclass1、subclass2是递进关系。同时下面的子类完全继承父类的方法,并且可以覆盖父类的方法。子类2拥有function1,function2,function3三个函数方法。function1的执行代码来自subclass1, function2的执行代码来自于subclass2。
右侧是类别。可以看到,无论如何扩展类的类别,最终就只有一个类class。类别可以说是类的不同方法的小集合,它把一个类的方法划分成不同的区块。请注意观察,每个类别块内的方法名称都没有重复的。这正类别的重要要求。
经过上面简单解释了解了这两点的基本区别,现在深入说一下类别。
在Objective-C语言设计之初,一个主要的哲学观点就是尽量让一个程序员维护庞大的代码集。根据结构化程序设计的经验出发,把一个大块代码划分成一些小块的代码更便于程序员管理。于是objc借用了smalltalk的categories概念。允许程序员把一系列功能相近的方法组织到一个单独的文件内,使得这些代码更容易识别。
与C和C++这种静态语言相比,Objective-C把类“类别”功能集成到了“运行时”里面。因此,Objective-C的类别允许程序员为已经存在的类添加新的方法而不需要重新编译旧的类。一旦一个类别加入,它可以访问该类所有方法和实例变量,包括私有变量。
类别不仅可以为原有类添加方法,而且如果类别方法与类内某个方法具有同样的方法签名(method signature),那么类别里的方法将会替换类的原有方法。这是类别的替换特性。利用这个特性,类别还可以用来修复一些巴格(bugs)。例如已经发布的框架出现漏洞,如果不便于重新发布新版本,可以使用类别替换特性修复漏洞。另外,由于类别有运行时级别的集成度,所以使得Cocoa程序安全性有所下降。许多黑客就是利用类别、posting2、Method Swizzling 等方法破解软件,或者为软件增加新功能。
值得注意的一点是,由于一个类的类别之间是平级关系。所以如果不同类别拥有相同的方法,这个调用结果是未知的:
Category methods should not override existing methods (class or instance). Two different categories implementing the same method results in undefined behavior.
Objective-C中类别有其局限的部分,就是你不能为原有的类添加变量,只能添加方法。当然方法里可以添加局部变量。在这个局限基础上就有其它语言做了进一步改进,例如TOM语言就为类别增加了添加类变量的能力。
自从Objective-C 2.0以后,语言引入了一个新的特性叫做类扩展(Class Extensions), 它可以看做是一类特殊的类别,可以给原有类增加新的属性和方法。类扩展常用来定义类的私有变量和方法。如果类别是为类增加外部方法的话,那么 类扩展就是用做类的内部拓展。
类扩展的外观很简单,就是一个类别后面括号内的名字为空:
@interface ClassName ()
@end
接下来,就可以给你的类里添加属性,方法了:
@interface XYZPerson (){
id _someCustomInstanceVariable;
}
@property NSObject *extraProperty;
- (void)assignUniqueIdentifier;
@end
总上所属,如果开发时候遇到无论如何都需要为类添加变量的情况,最好的选择就是子类。相反如果你只希望增加一些函数簇。类别是最好的选择。而类内部需要用到的私有变量和方法则最好写在类扩展里。
类别关注的重心是代码设计,把不同功能的方法分离开。在Objective-C里因为类别是运行时级别的特性,所以这种分离不仅体现在源码结构上,同时体现在运行时过程中。这意味着一个类别里的方法在程序运行中如果没有被调用,那么它就不会被加载到内存中。所以合理的使用类别会减少你的程序内存消耗。
所以给大家的建议是,每个Objective-C程序员都应该收集整理自己的一套NS类函数的类别扩展库。这对今后程序开发效率和掌控情况都有很大提高。