Category
Objective-C 允许你通过 categories 和类扩展来对已有的类中添加你自定义的方法。
使用 @ interface 关键字来声明一个 category ,就像标准的 Objective-C 类的描述一样,但并不表示这个 category 从任何一个子类继承。 另外它指定 category 的名称在括号内
@interface ClassName (CategoryName)
@end
Categories 可用于声明类方法或成员方法,但并非通常适合声明附加属性。
在一个 category 的接口中包含属性声明时编译器不会报错,但是不能在一个 category 中声明一个附加的成员变量。 这意味着,编译器不会为该属性合成任何成员变量,也不合成任何属性访问方法。 在类的实现过程中,你可以编写你自己的访问方法,但是你不能来跟踪该属性的值,除非原始类中已有了该成员变量。
避免 categories 方法名冲突
如果两个category定义了相同名字的方法,在运行时,只有一个方法会“赢”,并添加到 NSString 类中,另一个则成为未定义不起作用。
为了避免未定义的行为,最佳的做法是给框架类 categories 中的方法名添加一个前缀,就像你向你自己的类的名称添加一个前缀一样。
你可以选择使用和你自己的类的前缀相同的三个字母,但要小写以遵循方法命名的规则,然后在方法名称的其余部分之间用一个下划线连接。
@interface NSSortDescriptor (XYZAdditions)
+ (id)xyz_sortDescriptorWithKey:(NSString *)key ascending:(BOOL)ascending;
@end
Extension
用 extension 来实现类的扩展
类扩展与 category 有相似性,但在编译时它只能被添加到已有源代码的一类中(该类扩展和该类同时被编译)。
用于声明类扩展的语法类似于一个 category 声明的语法,看起来像这样:
@interface ClassName ()
@end
因为没有在括号内给定名称,所以类扩展通常称为匿名类。
类扩展可以向类中添加其自己的属性和成员变量。如果你在类扩展中声明一个属性,要像这样:
@interface XYZPerson ()
@property NSObject *extraProperty;
@end
编译器会自动合成相关的访问方法,以及一个成员变量,继承到主要的类。
如果你在一个类扩展中添加任何方法,这些必须在主要类中继承。
也可以使用一个类扩展来添加自定义的成员变量。这些变量在类扩展接口中的大括号内声明:
@interface XYZPerson () {
id _someCustomInstanceVariable;
}
...
@end
使用类扩展来隐藏私有信息
一个类的主要接口用于定义其他类将与之进行交互的方式。换句话说,它是类的公共部分。
类扩展通常用于扩展额外的私有方法或属性的公共接口以便在类本身的实现中使用。
@interface XYZPerson : NSObject
...
@property (readonly) NSString *uniqueIdentifier;
- (void)assignUniqueIdentifier;
@end
@interface XYZPerson ()
@property (readwrite) NSString *uniqueIdentifier;
@end
@implementation XYZPerson
...
@end
当其他源代码文件中的某段代码试图调用一个私有方法或设置一个只读属性的值时,编译器会报错,但利用动态运行功能使用其他方式调用这些方法是可以避免编译器错误的,例如通过使用由 NSObject 类提供的 performSelector 的方法。 你应该避免出现一个类的层次结构或者仅在必须的时候使用;相反主类接口应始终定义正确的"公共接口。