Extensions
Objective-C 语言中有一项叫做extensions 的设计,也可以用来拆分一个很大的class,语法与category 非常相似,但是不太一样。在语法上,extensions 像是一个没有名字的category,在class 名称之后直接加上空的括弧,而extensions 定义的method,需要放在原本的class 实现中。
以下是一个使用extensions 的例子:
@interface MyClass : NSObject
@end
@interface MyClass()
- (void)doSomthing;
@end
@implementation MyClass
- (void)doSomthing
{
}
@end
在@interface MyClass ()
这段代码中,我们并没有在括弧中定义任何名称,接着,doSomthing
又是直接在MyClass
中实现。extensions可以有几个用途:
拆分Header
如果我们就是打算实作一个很大的class,但是觉得header里头已经列出了太多的method和property,我们可以将一部分method 搬到extensions 的定义里头。
另外,extension 除了可以放method 之外,也可以放成员变量,而一个class 可以拥有不只一个extension,所以如果一个class 真的有非常非常多的method 与成员变数,我们可以把这些method 与成员变数,放在多个extension 中。
管理Private Methods
这其实是更常见的用途。我们在写一个class的时候,内部有一些method不需要、我们也不想要放在public header中,但是如果不将这些method放在header里头,又会出现一个困扰:在Xcode 4.3之前,如果这些private method在程式码中不放在其他method前面,其他的method在调用这些method的时候,compiler会不断跳出警告,而这种无关紧要的警告一多,我们往往会忽视真正重要的警告。
想要避免这些警告,要不就是把private method都放在最前面,但这样并不能完全解决问题,因为private method之间也会相互呼叫,花时间确认每个method之间的呼叫顺序并不是很经济的事;要不就是都用performSelector:
呼叫,这样问题更大,就像前面提到,在method改名、呼叫refactoring工具的时候,这样非常危险。
苹果提供的建议是,我们在.m 或.mm 档案开头的地方定义一个extensions,将private method 都放在这个地方,如此一来,其他method 就可以找到private method 的宣告。从Xcode 4 开始—至少到Xcode 7 都是如此,在Xcode 中所提供的file template 中,如果你选择建立一个UIViewController 的subclass,就可以看到在.m 档案的最前面,帮你预留了一块extensions 的宣告。
在这边也顺便提一下Swift里头的extension。在Swift语言中,我们可以直接使用extension
关键字,建立class的extension,扩充一个class; Swift的extension与Objective-C的category的主要差别是, Objective-C的category要给定一个名字,而Objective-C的extension是没有名字的category,至于Swift的extension则统一都没有名字。
所以,如果你有一个Swift class 叫做MyClass:
class MyClass {
}
只要这样就可以直接建立extension:
extension MyClass {
}
另外,Swift 除了可以用extension 扩充class 之外,甚至可以扩充protocol 与struct。我们会在后面讲delegate 的时候说明protocol。
protocol MyProtocol {
}
extension MyProtocol {
}
struct MyStruct {
}
extension MyStruct {
}