Swift工具類命名空間隔離
前言
OC 中一直一來就有一個很讓人頭疼的問題就是方法名或者類名重復(fù)的問題,特別是在使用第三方 SDK 中包含了一個與自己在項目中與用到的同一個第三方框架,這是一個很頭疼的問題.
遇到這種情況,你只有兩個選擇:
1.換一個相同功能的第三方框架
2.把這個第三方框架中的方法名和類名全改了
所以,一直一來在 OC 的第三方框架中,都加了前綴,如 AFNetworking, MJRefresh, YYModel.即使是在我們自己寫的類中,也會加上前綴
但是加上前綴也只是減小了重復(fù)的可能性,并不能完全的不會重復(fù)
然后,蘋果發(fā)布了 Swift,像許多優(yōu)秀的編程語言一樣,在 Swift 中避開了 OC 中的尷尬情況,采用用命名空間的概念.
然而在 Swift 中的命名空間是基于一個 Module 的,也就是一個 Module 是一個命名空間.這也就是為什么現(xiàn)在的 Snapkit 使用的時候會view.snp.xxxx
,Kingfisher 使用的時候要用imageView.kf.xxxx
.
但是在我們自己平時在寫一些工具類或者 Foundation框架的類的擴(kuò)展的時候,有可能會有一些方法與系統(tǒng)或者別人寫的方法重名,這就很尷尬了!
這個前言好像有點長了??
類型嵌套
不過好在 SWift 為我們提供了類型嵌套的方法,我們可以在一個類型(可以是類,結(jié)構(gòu)體,枚舉類型)里面去定義別一個類型,從而達(dá)到隔離內(nèi)部類型的方法,可以參考喵神的文章
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>為擴(kuò)展類型添加協(xié)議一致性
閱讀 SnapKit 和 Kingfisher 的代碼后,你會發(fā)現(xiàn)它們并沒有使用類型嵌套,而是是用了一個很巧妙的方法來實現(xiàn)的: 自定義一個類并且提供一個協(xié)議來完成
下面我們看一下如何隔離我們的工具類:
1.先定義一個泛型工具類
TTAUtils<Base>
,并提供一個對應(yīng)泛型的屬性和一個初始化方法2.定義一個泛型協(xié)議,在協(xié)議中定義一個工具類只讀的一個實例屬性和一個類型屬性,用來調(diào)用你工具類的方法,在協(xié)議擴(kuò)展中分類給定兩個默認(rèn)實現(xiàn),分別返回一個 TTAUtils 的實例和 TTAUtils 的類型
3.然后給你要擴(kuò)展的類型在擴(kuò)展中添加協(xié)議一致性
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 { }
上面的準(zhǔn)備工作做好了,下面我們來為類型添加協(xié)議一致性
/// 為 TTAUtils 類添加擴(kuò)展方法
extension TTAUtils where Base: UIImageView {
public func setImageWithURL(url: URL?, placeholderImage: UIImage?) {
print(url ?? "not a url")
}
}
如果添加的類型是結(jié)構(gòu)體類型,需要一些額外的工作:
/// 定義一個結(jié)構(gòu)體類型
public struct StringProxy {
fileprivate let base: StringTTAUtilsCompatiable
init(proxy: String) {
base = proxy
}
}
/// 為 String 結(jié)構(gòu)體添加協(xié)議一致性,并實現(xiàn)對應(yīng)的屬性 `getter`
extension String: TTAUtilsCompatiable {
public var tta: StringProxy {
return StringProxy(proxy: self)
}
}
/// 為自定義結(jié)構(gòu)體添加擴(kuò)展方法
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)
/// 結(jié)構(gòu)體類型
let string = "Hello world"
string.tta.printAString()
總結(jié)
以上兩種方法,我個人更推薦第二種方法(為擴(kuò)展類型添加協(xié)議一致性)
因為這種方法,可以讓你:
1.很靈活的擴(kuò)展任何想要擴(kuò)展的類型
2.調(diào)用起來可以與主流框架(SnapKit, Kingfisher) 類似,又可以與我們習(xí)慣的 OC 寫法想對應(yīng)!