前言
在面试时经常会被问到,什么是category,什么是继承,二者有什么区别,重写一个类是继承好还是分类号,为什么?
比较
- Category是一种为现有类扩展新的方法,而不需要继承或者改变现有类的方式。
- 继承是面向对象语言都有的一个特性,子类会继承父类的方法和属性。
如果新扩展的方法与原方法同名就不要使用category,因为系统有很多方法是用Category实现的,重写之后,会导致在Runtime的时候,只有一个方法会被执行,而哪个会被执行是undefined。
这样会导致所有引用了这个分类的方法都会遭到篡改,无法调用到原来的方法,而继承可以使用重写父类方法,并不会影响其他类的使用。
举个例子吧,我们通过分类扩展UIColor。
头文件
#import <UIKit/UIKit.h>
@interface UIColor (Extension)
+ (UIColor *)whiteColor;
+ (UIColor *)Ex_whiteColor;
@end
实现文件
#import "UIColor+Extension.h"
@implementation UIColor (Extension)
+ (UIColor *)whiteColor {
return [UIColor colorWithRed:0.0/255.0 green:0.0/255.0 blue: 0.0/255.0 alpha:1.0];
}
+ (UIColor *)Ex_whiteColor {
return [UIColor colorWithRed:0.0/255.0 green: 0.0/255.0 blue:0.0/255.0 alpha:1.0];
}
@end
[UIColor whiteColor];
是系统框架UIKit提供的类方法,假设我们通过分类扩展重写了+ (UIColor *)whiteColor;
方法,而且恰好#import "UIColor+Extension.h"
在预编译时就被引用了,那么所有调用[UIColor whiteColor]
设置颜色都会变成黑色而不是白色,这将会是一种灾难。
当然我们可以通过扩展新方法+ (UIColor *)Ex_whiteColor;
来达到这个目的,只要引入#import "UIColor+Extension.h"
,就可以调用+ (UIColor *)Ex_whiteColor;
。
Category的使用场景
- 当你在定义类的时候,在某些情况下(例如需求变更),你可能想要为其中的某个或几个类中添加方法。
- 一个类中包含了许多不同的方法需要实现,而这些方法需要不同团队的成员实现
- 当你在使用基础类库中的类时,你可能希望这些类实现一些你需要的方法。
遇到以上这些需求,Category可以帮助你解决问题。当然,使用Category也有些问题需要注意:
- Category可以访问原始类的实例变量,但不能添加变量,如果想添加变量,可以考虑通过继承创建子类。
- Category可以重载原始类的方法,但不推荐这么做,这么做的后果是你再也不能访问原来的方法。如果确实要重载,正确的选择是创建子类。
- 和普通接口有所区别的是,在分类的实现文件中可以不必实现所有声明的方法,只要你不去调用它。
总结
- 如果要重写现有类的方法,请考虑使用继承。
- 如果给现有类扩展属性,考虑使用继承(虽然category也可以通过runtime添加属性,建议使用继承)。
- 针对系统提供的一些类,例如:NSString,NSArray,NSNumber等类,考虑使用类别来进行方法扩展。
- 对于开发人员针对自己构建的类,对于大型而复杂的类,建议使用类别,这有助于提高可维护性。