分类和扩展
类别允许您将方法添加到现有的类—甚至添加到您没有源的类。Categories是一个强大的特性,它允许您扩展现有类的功能,而不需要子类化。通过使用类别,您还可以在多个文件中分发您自己的类的实现。类扩展类似,但是允许在主类@interface块之外的位置为类声明额外的api
向类中添加方法
您可以通过在类名下的接口文件中声明方法,并在同名的实现文件中定义方法,从而向类中添加方法。类别名称表示方法是对在别处声明的类的添加,而不是新类。但是,不能使用类别向类中添加其他实例变量。
类别添加的方法成为类类型的一部分。例如,添加到类别中的NSArray类中的方法包含在编译器期望NSArray实例在它的指令表中具有的方法中。但是,在子类中添加到NSArray类的方法不包括在NSArray类型中。(这只对静态类型的对象很重要,因为静态类型是编译器了解对象类的唯一方法。)
Category方法可以做类中定义的方法可以做的任何事情。在运行时,没有区别。类添加到类中的方法由类的所有子类继承,就像其他方法一样。
类接口的声明看起来非常像类接口声明——除了类名后面的括号中列出了类名,而没有提到超类。除非它的方法不访问类的任何实例变量,否则类必须为它扩展的类导入接口文件:
#import "ClassName.h"
@interface ClassName ( CategoryName )
//方法声明
@end
注意,类别不能为类声明额外的实例变量;它只包含方法。但是,类范围内的所有实例变量也属于类别范围。这包括类声明的所有实例变量,甚至包括声明@private的实例变量。
可以添加到类中的类别数量没有限制,但是每个类别名称必须不同,并且每个类别名称都应该声明和定义不同的方法集。
扩展
类扩展类似于匿名类别,只是它们声明的方法必须在对应类的主@implementation块中实现。使用Clang/LLVM 2.0编译器,还可以在类扩展中声明属性和实例变量。
类扩展的一个常见用途是重新声明属性,该属性公开声明为只读,私有声明为readwrite:
@interface MyClass : NSObject
@property (retain, readonly) float value;
@end
// 私有扩展名,通常隐藏在主实现文件中。
@interface MyClass ()
@property (retain, readwrite) float value;
@end
注意(与类别相反)第二个@interface块的括号中没有给出名称。
通常,一个类有一个公开声明的API,然后又有一些单独声明的方法,仅供类或类所在的框架使用。类扩展允许您在主类@interface块之外的位置为类声明其他必需的方法,如下例所示:
@interface MyClass : NSObject
- (float)value;
@end
@interface MyClass () {
float value;
}
- (void)setValue:(float)newValue;
@end
@implementation MyClass
- (float)value {
return value;
}
- (void)setValue:(float)newValue {
value = newValue;
}
@end
方法的实现必须出现在类的主@implementation块中(您不能在类别中实现它)。如果不是这样,编译器会发出警告,说明它无法找到setValue:的方法定义。