Swift工具類命名空間隔離
前言
OC 中一直一來就有一個很讓人頭疼的問題就是方法名或者類名重復的問題,特別是在使用第三方 SDK 中包含了一個與自己在項目中與用到的同一個第三方框架,這是一個很頭疼的問題.
遇到這種情況,你只有兩個選擇:
1.換一個相同功能的第三方框架
2.把這個第三方框架中的方法名和類名全改了
所以,一直一來在 OC 的第三方框架中,都加了前綴,如 AFNetworking, MJRefresh, YYModel.即使是在我們自己寫的類中,也會加上前綴
但是加上前綴也只是減小了重復的可能性,并不能完全的不會重復
然后,蘋果發布了 Swift,像許多優秀的編程語言一樣,在 Swift 中避開了 OC 中的尷尬情況,采用用命名空間的概念.
然而在 Swift 中的命名空間是基于一個 Module 的,也就是一個 Module 是一個命名空間.這也就是為什么現在的 Snapkit 使用的時候會view.snp.xxxx
,Kingfisher 使用的時候要用imageView.kf.xxxx
.
但是在我們自己平時在寫一些工具類或者 Foundation框架的類的擴展的時候,有可能會有一些方法與系統或者別人寫的方法重名,這就很尷尬了!
這個前言好像有點長了??
類型嵌套
不過好在 SWift 為我們提供了類型嵌套的方法,我們可以在一個類型(可以是類,結構體,枚舉類型)里面去定義別一個類型,從而達到隔離內部類型的方法,可以參考喵神的文章
struct MyOuterClass1 {
class MyClass {
class func hello() {
print("hello from MyClassContainer1")
}
}
}
struct MyOuterClass2 {
class MyClass {
class func hello() {
print("hello from MyClassContainer2")
}
}
}
使用時:
MyOuterClass1.MyClass.hello()
MyOuterClass2.MyClass.hello()
<a name="protocol"></a>為擴展類型添加協議一致性
閱讀 SnapKit 和 Kingfisher 的代碼后,你會發現它們并沒有使用類型嵌套,而是是用了一個很巧妙的方法來實現的: 自定義一個類并且提供一個協議來完成
下面我們看一下如何隔離我們的工具類:
1.先定義一個泛型工具類
TTAUtils<Base>
,并提供一個對應泛型的屬性和一個初始化方法2.定義一個泛型協議,在協議中定義一個工具類只讀的一個實例屬性和一個類型屬性,用來調用你工具類的方法,在協議擴展中分類給定兩個默認實現,分別返回一個 TTAUtils 的實例和 TTAUtils 的類型
3.然后給你要擴展的類型在擴展中添加協議一致性
Show you the code!
public final class TTAUtils<Base> {
public let base: Base
public init(_ base: Base) {
self.base = base
}
}
public protocol TTAUtilsCompatiable {
associatedtype CompatiableType
var tta: CompatiableType { get }
static var ttaClass: CompatiableType.Type { get }
}
public extension TTAUtilsCompatiable {
public var tta: TTAUtils<Self> {
return TTAUtils(self)
}
public static var ttaClass: TTAUtils<Self>.Type {
return TTAUtils<Self>.self
}
}
extension NSObject: TTAUtilsCompatiable { }
上面的準備工作做好了,下面我們來為類型添加協議一致性
/// 為 TTAUtils 類添加擴展方法
extension TTAUtils where Base: UIImageView {
public func setImageWithURL(url: URL?, placeholderImage: UIImage?) {
print(url ?? "not a url")
}
}
如果添加的類型是結構體類型,需要一些額外的工作:
/// 定義一個結構體類型
public struct StringProxy {
fileprivate let base: StringTTAUtilsCompatiable
init(proxy: String) {
base = proxy
}
}
/// 為 String 結構體添加協議一致性,并實現對應的屬性 `getter`
extension String: TTAUtilsCompatiable {
public var tta: StringProxy {
return StringProxy(proxy: self)
}
}
/// 為自定義結構體添加擴展方法
extension StringProxy {
public func printAString() {
print(base)
}
}
使用:
/// 類類型
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 80, height: 80))
imageView.backgroundColor = .blue
imageView.center = aView.center
aView.addSubview(imageView)
imageView.tta.setImageWithURL(url: URL(string: "Here is a image url string"), placeholderImage: nil)
/// 結構體類型
let string = "Hello world"
string.tta.printAString()
總結
以上兩種方法,我個人更推薦第二種方法(為擴展類型添加協議一致性)
因為這種方法,可以讓你:
1.很靈活的擴展任何想要擴展的類型
2.調用起來可以與主流框架(SnapKit, Kingfisher) 類似,又可以與我們習慣的 OC 寫法想對應!