Swift
命名前綴
Swift
的命名空間是基于模塊(module
),每一個module
代表了一個Swift
中的一個命名空間
// ModuleA.swift
// 這個文件存在于 ModuleA,非主工程 中
public class MyClass {
class func hello() {
print("hello from ModuleA")
}
}
// MyApp.swift
// 這個文件存在于 app 的主 target 中
class MyClass {
class func hello() {
print("hello from ModuleB")
}
}
如果我們需要在主工程(target
)中,調(diào)用非主工程里的ModuleA
里相同的函數(shù)hello
;我們只需要加上ModuleA
的target
名去訪問即可。
// 使用哪個 MyClass,取決于是在哪個 target 中調(diào)用
ModuleA.MyClass.hello()
添加自己的命名空間
初級寫法
聲明協(xié)議Framable
public protocol Framable {
var x: CGFloat { get set }
var y: CGFloat { get set }
}
實現(xiàn)協(xié)議Framable
struct BaseFrame: Framable {
let view: UIView
init(view: UIView) {
self.view = view
}
public var x: CGFloat {
get { return view.frame.origin.x }
set { view.frame.origin.x = newValue }
}
public var y: CGFloat {
get { return view.frame.origin.y }
set { view.frame.origin.y = newValue }
}
}
實現(xiàn)UIView
命名前綴擴展
extension UIView {
public var cx: Framable {
return BaseFrame(view: self)
}
}
使用
self.view.cx.x = 10
進階寫法
以上固然可以實現(xiàn)命名空間前綴,但是還是不夠優(yōu)雅不夠Swift
。
為此我們可以利用泛型和協(xié)議來更高效的實現(xiàn)命名空間
定義泛型結(jié)構(gòu)體
定義一個泛型結(jié)構(gòu)體,使用泛型Base
public struct CXKit<Base> {
let base: Base
init(_ base: Base) {
self.base = base
}
}
定義泛型協(xié)議
定義了一個 CXNameSpace
協(xié)議,這個協(xié)議代表了支持 namespace
形式的擴展。并利用extension
為這個協(xié)議 添加了默認實現(xiàn)。
public protocol CXNameSpace {
// associatedtype 相當于一個占位符,而不能表示具體的類型。具體的類型需要讓實現(xiàn)的類來指定。
associatedtype T
var cx: CXKit<T> { get }
}
public extension CXNameSpace {
var cx: CXKit<Self> {
return CXKit(self)
}
static var cx: CXKit<Self>.Type {
return CXKit<Self>.self
}
}
實現(xiàn)命名空間cx
擴展
extension UIView: CXNameSpace { }
extension CXKit where Base: UIView {
public var x: CGFloat {
get { return base.frame.origin.x }
set { base.frame.origin.x = newValue }
}
}
使用
self.view.cx.x = 10
在對CXKit
做extension
時, where
后面的 Base
約束可以使用 ==
或者 :
區(qū)別是:
- 如果擴展的是值類型,比如
String,Date
等 ,就必須使用==
- 如果擴展的是類,則兩者都可以使用,區(qū)別是如果使用
==
來約束,則擴展方法只對本類生效,子類無法使用。如果想要在子類也使用擴展方法,則使用:
來約束。