Swift擴展方法(Kingfisher)

我們平時用swift寫第三方擴展(OC中的分類)時,可能會直接就往擴展里面寫方法,簡單又方便,然而當我們看一些常用你的三方(例如:Kingfisher、SnapKit)等,都會用一個簡單的參數(shù)引出(例如:kf、snp),下面來探索一下怎么用的,然后在總結(jié)其優(yōu)缺點
SnapKit擴展方式簡要思考
以 SnapKit為例,使用如下,發(fā)現(xiàn)引入了 snp

var iv = UIImageView();
iv.snp.makeConstraints { make in
}

中間變量 snp 如下所示,ConstraintView是統(tǒng)一不同平臺的重命名(別名)

public extension ConstraintView {
    var snp: ConstraintViewDSL {
        return ConstraintViewDSL(view: self)
    }
}

其以前版本也是直接將 left 等加上前綴 snp_,直接調(diào)用,而加入前綴我想大家一眼就看出來目的了,沒錯避免與其他擴展重名,現(xiàn)在也已經(jīng)改成了引入snp的方式,來間接調(diào)用,實際邏輯都通過 snp 來調(diào)用,個人猜測也是借鑒了主流的應(yīng)用來更新的,調(diào)用時,至少分類 API 整潔了

優(yōu)缺點:

  • 1、引入中間變量 snp 之后,首先感覺到的就是,我們的分類在調(diào)用的時 -- 候,明顯沒有那么多雜亂的方法了(這種方式OC其實也可以借鑒)
  • 2、另外也可以取消了前綴,減少了代碼量,并且當與其他類出現(xiàn)重名的時候,只需要替換 snp 的變量名字即可,不需要替換全部方法,減少了命名阻礙
  • 3、不同三方之間通過引入該參數(shù),讓我們的調(diào)用模塊標識更明顯,功能模塊也更清晰,可維護性更強

Kingfisher擴展方式簡要思考
以 Kingfisher為例,使用如下,發(fā)現(xiàn)引入了 kf

var iv = UIImageView();
iv.kf.setImage(with: URL(string: "http://www.baidu.com"))

另外其在使用過程中,通過充分利用 swift 特性,比 SnapKit 使用上更優(yōu)雅高效一些

//聲明一個基礎(chǔ)協(xié)議,必須為 AnyObject 類型,可用于后續(xù)給基礎(chǔ)類添加協(xié)議
public protocol KingfisherCompatible: AnyObject { }

//擴展實現(xiàn)該基礎(chǔ)協(xié)議,以便于方便讓我們的組件能夠直接通過 .kf 直接調(diào)用里面的方法
//此 kf 和 snap 類似,只不過添加了一個泛型,用于不同類之間進行擴展限制
extension KingfisherCompatible {
   public var kf: KingfisherWrapper<Self> {
       get { return KingfisherWrapper(self) }
       set { }
   }
}

//通過泛型頂一個一個基礎(chǔ)類,通過該基礎(chǔ)類可以獲取我們被擴展的組件
//且通過該基礎(chǔ)類的泛型,可以分別給不同類型添加不同擴展方法
public struct KingfisherWrapper<Base> {
   public let base: Base
   public init(_ base: Base) {
       self.base = base
   }
}

//當遵循協(xié)議的類為 UIImage 的時候,為其擴展方法
extension KingfisherWrapper where Base: KFCrossPlatformImage {
   ...
}
//當遵循協(xié)議的類為 KFCrossPlatformImageView 的時候,為其擴展方法
extension KingfisherWrapper where Base: KFCrossPlatformImageView {
   ...
}
...

//上面僅僅是定義了一個擴展后可以使用的協(xié)議,并未應(yīng)用到我們的基礎(chǔ)組件中
//因此只需要給基礎(chǔ)組件添加擴展,遵循我們的協(xié)議即可
extension KFCrossPlatformImageView: KingfisherCompatible { }

沒見到名字的View 是為了不同平臺統(tǒng)一名字起的別名,如下所示(打消疑慮專用)

#if os(iOS) || os(tvOS)
    public typealias ConstraintView = UIView
#else
    public typealias ConstraintView = NSView
#endif

優(yōu)缺點:

  • 1、引入中間變量 kf 之后,首先感覺到的就是,我們的分類在調(diào)用的時候,明顯沒有那么多雜亂的方法了(這種方式OC其實也可以借鑒)
  • 2、另外也可以取消了前綴,減少了代碼量,并且當與其他類出現(xiàn)重名的時候,只需要替換 kf 的變量名字即可,不需要替換全部方法,減少了命名阻礙
  • 3、不同三方之間通過引入該參數(shù),讓我們的調(diào)用模塊標識更明顯,功能模塊也更清晰,可維護性更強
  • 4、引入?yún)f(xié)議和泛型,通過協(xié)議統(tǒng)一引入同一個中間變量,通過泛型給不同的分類擴展出不同的方法,減少無效方法和代碼等,結(jié)構(gòu)更清晰,某種角度上,其為進階版的擴展方式

自行模仿嘗試

public protocol LDCompatible: AnyObject { }

extension LDCompatible {
    public var dd: LDWrapper<Self> {
        get { return LDWrapper(self) }
        set {  }
    }
}

public struct LDWrapper<T> {
    public let base: T
    public init(_ base: T) {
        self.base = base
    }
}

extension UIView: DDCompatible {}
extension LDWrapper where T: UIView {
    func setBg(_ bg: UIColor?) {
        self.base.backgroundColor = bg
    }
}

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let v = UIView()
        v.ld.setBg(UIColor.white)
    }
}

當我們自己為默認組件擴展內(nèi)容時,如果只擴展一個類和功能,可以像 snp 一樣,直接引入中間變量擴展即可,如果我們的擴展了多個分類,而隸屬于一個模塊,那么可以模仿 Kingfisher,讓我們的功能更清晰

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 定義命名空間:是用來組織和重用代碼的。如同名字一樣的意思,NameSpace(名字空間),之所以出來這樣一個東西,...
    Mg明明就是你閱讀 1,697評論 1 2
  • 用到的組件 1、通過CocoaPods安裝 2、第三方類庫安裝 3、第三方服務(wù) 友盟社會化分享組件 友盟用戶反饋 ...
    SunnyLeong閱讀 15,212評論 1 180
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,833評論 4 61
  • Swift工具類命名空間隔離 前言 OC 中一直一來就有一個很讓人頭疼的問題就是方法名或者類名重復(fù)的問題,特別是在...
    TobyoTenma閱讀 1,765評論 1 1
  • 轉(zhuǎn)自:https://github.com/KQAppleDev/SwiftLearnhttp://blog.cs...
    kangqiao182閱讀 1,049評論 1 1

友情鏈接更多精彩內(nèi)容