相比于OC時(shí)代的完全沒(méi)有命名空間,Swift可以通過(guò)巧妙的辦法,實(shí)現(xiàn)幾乎等同于命名空間的效果。
需求
現(xiàn)在我們希望為UIColor類(lèi)增加一個(gè)擴(kuò)展方法,根據(jù)其自身顏色生成圖像UIImage。
在沒(méi)有命名空間的時(shí)代,可能結(jié)果是這樣子的:
let image = UIColor.blue.image
或者為避免與其它框架API同名,可能結(jié)果會(huì)變成這樣子:
let image = UIColor.blue.jx_image
當(dāng)然這種風(fēng)格非常地OC。
那有沒(méi)有優(yōu)雅一點(diǎn)的辦法來(lái)代替OC Style?比如能寫(xiě)成這樣子就好了:
let image = UIColor.blue.jx.image
Swift3繞一下路,也是可以做到的。姑且把中間的.jx叫做命名空間(Namespace),沒(méi)錯(cuò),抄了一下C#們的叫法。
定義命名空間
具體的做法通過(guò)擴(kuò)展特定的協(xié)議來(lái)達(dá)到目的。
我們需要定義兩個(gè)協(xié)議,其中一個(gè)是固定的寫(xiě)法:
/// 類(lèi)型協(xié)議
protocol TypeWrapperProtocol {
associatedtype WrappedType
var wrappedValue: WrappedType { get }
init(value: WrappedType)
}
struct NamespaceWrapper<T>: TypeWrapperProtocol {
let wrappedValue: T
init(value: T) {
self.wrappedValue = value
}
}
另一個(gè)協(xié)議基本上也是固定的寫(xiě)法,只是根據(jù)我們的需要,更改其內(nèi)的命名空間名字即可。
比如我需要一個(gè)名為jx的命名空間,就可以這樣寫(xiě):
/// 命名空間協(xié)議
protocol NamespaceWrappable {
associatedtype WrapperType
var jx: WrapperType { get }
static var jx: WrapperType.Type { get }
}
extension NamespaceWrappable {
var jx: NamespaceWrapper<Self> {
return NamespaceWrapper(value: self)
}
static var jx: NamespaceWrapper<Self>.Type {
return NamespaceWrapper.self
}
}
需要什么樣的命名空間,就把其中的jx改成你希望的名字。
使用命名空間
實(shí)際上我們需要擴(kuò)展的類(lèi)不是UIColor,而是協(xié)議。
這里分兩步,第一步是讓需要擴(kuò)展的類(lèi)遵循協(xié)議NamespaceWrappable:
extension UIColor: NamespaceWrappable {}
第二步是擴(kuò)展協(xié)議TypeWrapperProtocol:
extension TypeWrapperProtocol where WrappedType == UIColor {
/// 用自身顏色生成UIImage
var image: UIImage? {
let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
UIGraphicsBeginImageContext(rect.size)
let context = UIGraphicsGetCurrentContext()
context?.setFillColor(wrappedValue.cgColor)
context?.fill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
return image
}
}
在擴(kuò)展的方法中,self代表的是協(xié)議,而不是目標(biāo)擴(kuò)展類(lèi)。那要用到self怎么辦?用wrappedValue吧,它就是我們的目標(biāo)類(lèi)/實(shí)例。
驗(yàn)證
現(xiàn)在可以愉快地玩耍了:
let image = UIColor.blue.jx.image
使用了命名空間后,還有一個(gè)優(yōu)點(diǎn)就是可以利用Xcode的代碼補(bǔ)全。

相比在打出.im后Xcode會(huì)彈出一大堆匹配到im兩字母的方法,使用了命名空間后,點(diǎn)出.jx.時(shí),Xcode就只會(huì)提示此命名空間內(nèi)的方法/屬性。特別是String和UIView這種有巨量方法的類(lèi),只要打出命名空間就可以快速過(guò)濾不需要的方法。