剖析:擴(kuò)展組合系統(tǒng)與協(xié)議導(dǎo)向設(shè)計是如何讓DSL無限可擴(kuò)展的)
UIKitPlus架構(gòu)剖析擴(kuò)展組合系統(tǒng)與協(xié)議導(dǎo)向設(shè)計是如何讓DSL無限可擴(kuò)展的【免費(fèi)下載鏈接】UIKitPlus Declarative UIKit with LivePreview for iOS9 (best alternative to SwiftUI)項(xiàng)目地址: https://gitcode.com/gh_mirrors/ui/UIKitPlusUIKitPlus 是一個基于 UIKit 和 AppKit 的聲明式 UI 框架iOS 9 可用自帶 SwiftUI 驅(qū)動的熱預(yù)覽 LivePreview被很多開發(fā)者稱為 SwiftUI 之外的最佳替代。這篇文章從源碼角度剖析它的兩大核心架構(gòu)機(jī)制——擴(kuò)展組合系統(tǒng)與協(xié)議導(dǎo)向設(shè)計Protocol-Oriented Design看看這個聲明式 DSL 是如何做到幾乎無限可擴(kuò)展的。一、先用 30 秒認(rèn)識它聲明式 DSL 長什么樣傳統(tǒng) UIKit 里創(chuàng)建一個居中按鈕需要寫十幾行代碼實(shí)例化、設(shè)類型、加子視圖、寫 4 條 NSLayoutConstraint。UIKitPlus 只需要一行鏈?zhǔn)秸{(diào)用Button(Click me).width(300).centerInSuperview()這種點(diǎn)號鏈?zhǔn)秸{(diào)用就是 DSL領(lǐng)域特定語言。而這篇文章要回答的問題是為什么 UIKitPlus 的 DSL 可以不斷長出.background()、.shadow()、.tap()、.corners()等上百個方法卻幾乎不修改任何已有代碼答案藏在兩類文件里Classes/Extensions/下的擴(kuò)展組合系統(tǒng)和Classes/Protocols/下的協(xié)議導(dǎo)向能力。二、一切的地基DeclarativeProtocol 核心協(xié)議整個 DSL 只有一個根協(xié)議DeclarativeProtocol。它定義了所有聲明式視圖的公共語法declarativeView拿到真實(shí)的UIView/NSView隨時可以回落到原生 UIKitproperties一個屬性背包存放顏色、邊框、手勢等所有配置width、height、top、leading…… 一組可讀寫的約束屬性。let v UView() v.width 100 // 直接寫屬性底層自動創(chuàng)建/更新約束 v.width 200 // 再改一次自動變成更新約束正是這一層把AutoLayout 約束變成了普通屬性賦值這也是后面無限擴(kuò)展的前提所有擴(kuò)展方法都不需要關(guān)心視圖類型只需要依賴這個協(xié)議。跨平臺同樣由它決定BaseView 只是一個類型別名iOS 上是UIViewmacOS 上是NSView同一套 DSL 在兩端通用。三、擴(kuò)展組合系統(tǒng)一個文件 一個功能開關(guān)打開 Classes/Extensions/ 目錄你會看到近 40 個DeclarativeProtocolXXX.swift文件每個文件負(fù)責(zé)一個功能域擴(kuò)展文件提供的能力DeclarativeProtocolBackground.swift.background(.red)背景色DeclarativeProtocolConstraintsSolo.swift.width()、.height()等尺寸約束DeclarativeProtocolCorners.swift.corners()圓角DeclarativeProtocolShadow.swift.shadow()陰影DeclarativeProtocolTap.swift.tap()點(diǎn)擊手勢每個文件的套路完全一樣給AnyDeclarativeProtocol核心協(xié)議的內(nèi)部聚合體寫一個 Swift extension聲明新方法。這就是擴(kuò)展組合系統(tǒng)的精髓——典型的開閉原則對擴(kuò)展開放想給所有視圖加一個新 DSL 方法新建一個DeclarativeProtocolMyFeature.swift即可框架核心零改動對修改關(guān)閉各功能域互不干擾.shadow()的代碼不知道也不關(guān)心.background()存在組合自動生效因?yàn)閿U(kuò)展都落在同一個協(xié)議上UButton、UView、UTextField…… 所有視圖自動獲得全部能力無需逐個適配。 對新手的一句話總結(jié)UIKitPlus 的 DSL 不是寫死的語法而是由一組可插拔的協(xié)議擴(kuò)展拼裝出來的。想加新指令加個文件就行。四、協(xié)議導(dǎo)向設(shè)計能力協(xié)議 默認(rèn)實(shí)現(xiàn) 白拿的功能第二個機(jī)制是Classes/Protocols/目錄里超過 60 個能力協(xié)議Capability Protocol。以背景色為例看 BackgroundColorable協(xié)議只聲明你會做什么background(UColor)、background(Int)、background(StateUColor)默認(rèn)實(shí)現(xiàn)寫在擴(kuò)展里監(jiān)聽State、自動處理值變化、調(diào)用內(nèi)部落點(diǎn)_setBackgroundColor視圖只要遵循協(xié)議就白拿整套功能。這套模式帶來三個好處按需采納Textable只給文本類視圖Scrollable只給滾動類視圖能力邊界清晰多態(tài)復(fù)用同一段默認(rèn)實(shí)現(xiàn)可以被UButton和UTextView共享沒有一行重復(fù)分層清晰面向用戶的公開協(xié)議之下還有一層內(nèi)部協(xié)議如 DeclarativeProtocolInternal 中的__width、__height約束狀態(tài)量把實(shí)現(xiàn)細(xì)節(jié)擋在圍墻花園里——公開 API 干凈內(nèi)部卻可以隨便重構(gòu)。五、膠水層State 狀態(tài)系統(tǒng)與自動資源回收DSL 之所以聰明是因?yàn)槊總€屬性背后都是一個響應(yīng)式StateT見 Classes/Structs/State.swift。例如UState var expanded false UView().width($expanded.map { $0 ? 200 : 100 }) // 狀態(tài)一變寬度自動重算但誰負(fù)責(zé)注銷監(jiān)聽、誰負(fù)責(zé)釋放是個經(jīng)典痛點(diǎn)。UIKitPlus 的解法非常優(yōu)雅每個視圖內(nèi)部持有一個stateBindingHolder見 PropertiesInternal而狀態(tài)監(jiān)聽在注冊時會通過 holdInStateBindingOwnerIfAvailable自動掛靠到所屬視圖上。視圖銷毀 → holder 隨之釋放 → 所有監(jiān)聽自動注銷。新手不需要寫任何deinit也不會遇到監(jiān)聽泄漏導(dǎo)致視圖卡死的坑。六、動手試試3 步給 DSL 加一個新指令理解了上面三塊你就能自己擴(kuò)展 DSL 了以給所有視圖加.hatch()網(wǎng)格紋理為例寫能力協(xié)議新建Hatchable.swift聲明func hatch(_ color: UColor) - Self寫默認(rèn)實(shí)現(xiàn)在協(xié)議擴(kuò)展中實(shí)現(xiàn)它通過properties存儲配置并調(diào)用內(nèi)部方法落到declarativeView.layer讓視圖采納在目標(biāo)視圖類型上聲明遵循Hatchable完事——.hatch(.gray)立刻出現(xiàn)在 DSL 鏈上且支持State響應(yīng)式版本照抄background的寫法即可。更多現(xiàn)成模式可以參考 Docs/Gestures.md 中手勢擴(kuò)展的實(shí)現(xiàn)思路。七、快速上手 UIKitPlus 想邊讀邊試克隆倉庫git clone https://gitcode.com/gh_mirrors/ui/UIKitPlus然后在 Xcode 中通過 SPM 添加包依賴選擇UIKitPlus產(chǎn)品鏈接到你的 App target也支持 CocoaPods見 UIKit-Plus.podspec。倉庫自帶 3 套 Xcode 工程模板iOS / macOS / 多平臺位于Templates/目錄新建項(xiàng)目即可直接開寫。八、總結(jié)為什么這套架構(gòu)值得學(xué)機(jī)制解決的問題對應(yīng)源碼核心根協(xié)議統(tǒng)一DSL 語法約束變屬性Classes/Protocols/DeclarativeProtocol.swift擴(kuò)展組合系統(tǒng)加功能不改核心代碼Classes/Extensions/ 下 39 個DeclarativeProtocol*.swift協(xié)議導(dǎo)向能力功能按需采納、默認(rèn)實(shí)現(xiàn)共享Classes/Protocols/ 下 60 能力協(xié)議State 自動回收響應(yīng)式更新且無監(jiān)聽泄漏Classes/Protocols/StateBindingOwner.swift一句話收尾UIKitPlus 把聲明式 DSL拆成了協(xié)議能力 擴(kuò)展功能單元 狀態(tài)響應(yīng)式膠水三層積木。你不需要讀懂全部源碼只要看懂任意一個DeclarativeProtocolXXX.swift就已經(jīng)掌握了給整個 DSL 加新指令的全部知識——這就是無限可擴(kuò)展的真正含義。【免費(fèi)下載鏈接】UIKitPlus Declarative UIKit with LivePreview for iOS9 (best alternative to SwiftUI)項(xiàng)目地址: https://gitcode.com/gh_mirrors/ui/UIKitPlus創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考