Swift工具類命名空間隔離

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 寫法想對應!

Where is the code?

Here is the Code

來自: https://www.tobyotenma.top/blog/?p=92

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 發現 關注 消息 iOS 第三方庫、插件、知名博客總結 作者大灰狼的小綿羊哥哥關注 2017.06.26 09:4...
    肇東周閱讀 12,241評論 4 61
  • 文|趙曉璃 寫在前面的話: 不知你有沒有這樣的困惑,在職場如戰場的嚴峻形勢下,你想溝通卻苦于沒有方法,怕說錯了惹麻...
    趙曉璃閱讀 2,312評論 14 81
  • 隨時間的磨礪 總要經歷孤單! 總要經歷難過! 總要經歷失敗! 總要經歷脆弱! 總要經歷拼搏! 總要經歷磨難! 學會...
    紫竹_徐芳閱讀 342評論 0 0