另辟蹊径--极简Swifty路由
另辟蹊徑--極簡Swifty路由
1. 前言
在組件化通信方案的設計之初,盡管我們是純Swift的組件化,我也一直難逃窠臼的想用注冊(無論是注冊協(xié)議還是注冊URL)的方式來解決問題,或者采用CTMediator的Target-Action方式,具體幾種組件化方案的實現(xiàn)與利弊見文章:iOS 組件化 —— 路由設計思路分析??
2. 彎路(經(jīng)驗)
最開始設計的組件化解決方案,因為作為一個電商項目(才不是這個原因),所以我僅采用了URL注冊的方式,我一直力求的它應該具備的特性如下:
其實3、4,已經(jīng)跳出了組件路由設計的范疇。確切的說應該是模塊解耦的范疇。
2.1 實現(xiàn)
我把router設計成單例,目的是保證其持有的["String": func]的字典的唯一確定性,其中func作為閉包形式,傳入?yún)?shù)返回ViewController。那么注冊環(huán)節(jié)就顯而易見的為register(_ key: String, value: func),調(diào)用就會根據(jù)key,執(zhí)行閉包func返回ViewController,以此解決1。
在對其中key的設計使用上,因為注冊方與調(diào)用方都會用到,所以我們將其寫在公共組件內(nèi),又因為key會附帶傳一些簡單的值,所以我又加了一個方法對key進行賦值處理操作,目的是為了保證第3條。
在模塊解耦問題的處理上,我設計了一個繼承AppDelegate方法的協(xié)議,暫稱為AppLifeCycle,同時添加了一些方法用于初始化注冊操作。再又設計了一個腳本,可以將遵循AppLifeCycle的實例生成一個plist文件,這樣在App啟動時候,一個方法調(diào)用就實現(xiàn)所有路由注冊功能,以此解決4、5。
對于第7點,在設計之初因為公司還沒有服務器端動態(tài)下發(fā)的功能,所以又加了中間件做fallBack處理(當然也都沒用上)。
3. Swifty組件化
雖然原有的路由設計與模塊解耦方案已經(jīng)支持現(xiàn)階段業(yè)務需求,但是使用上過于復雜,不夠友好,而且也沒用上多少swift的特性,反而這些實現(xiàn),如果用Objective-c實現(xiàn)起來,會更方便一些,比如腳本生成plist,OC都可以不需要。
最近有同事在對路由做抽離精簡,僅抽出router部分,主要在接口設計上進行優(yōu)化。我在看完后對一些功能點提了優(yōu)化可能,后續(xù)一直的交流溝通過程中,突然想到,我可以用Protocol Witness Table來實現(xiàn)這個路由啊!
其原理是: swift會維護一個Protocol Witness Table, 此表會保存實現(xiàn)了protocol協(xié)議的方法的指針地址,當我們調(diào)用方法時,是通過獲取對象的內(nèi)存地址和方法的位移去查找的。
所以我們可以用一個協(xié)議定義入?yún)?#xff0c;一個協(xié)議定義實現(xiàn),同一個Enum(建議使用的)去實現(xiàn),即可實現(xiàn)功能。
這種方式類似于target-action,無需注冊,接口約定,還具有其他一些優(yōu)點:
那么如此,我們的路由設計的核心代碼,如下:
public protocol MediatorTargetType {} // 用于接口定義,約束接口public protocol MediatorSourceType { // 用于枚舉實現(xiàn)var viewController: UIViewController? { get } }復制代碼target需要遵循的協(xié)議就這么些。
mediator需要遵循的協(xié)議與實現(xiàn):
public protocol SwiftyMediatorType {func viewController(of target: MediatorTargetType) -> UIViewController? }extension SwiftyMediator: SwiftyMediatorType {public func viewController(of target: MediatorTargetType) -> UIViewController? {guard let t = target as? MediatorSourceType else {print("MEDIATOR WARNINIG: \(target) does not conform to MediatorSourceType")return nil}guard let viewController = t.viewController else { return nil }return viewController} }復制代碼以上即是核心代碼。 通過接口收束,需要傳入MediatorTargetType,嘗試轉(zhuǎn)換成目標類型MediatorSourceType,以此返回viewController。
4. 使用
在使用中,我們?nèi)匀恍枰粋€公共的組件庫,對路由目標進行定義。假設這個庫叫MediatorTargets,其內(nèi)容如下:
public enum ModuleAMediatorType: MediatorTargetType {case home(title: String)case personal(color: UIColor) }復制代碼然后在我們寫的模塊庫中,此時我們是路由目標的提供方,如3中核心代碼所示,我們需要 讓ModuleAMediatorType再遵循協(xié)議MediatorSourceType,以此支持ModuleAMediatorType返回viewController:
import SwiftyMediator import MediatorTargetsextension ModuleAMediatorType: MediatorSourceType {public var viewController: UIViewController? {switch self {case .home(let title):let vc = UIViewController()vc.view.backgroundColor = .green vc.title = titlereturn vccase .personal(let color):let vc = PresentedViewController()vc.view.backgroundColor = colorvc.title = "Presented"return vc}} } 復制代碼那么實現(xiàn)方的調(diào)用,只需要:
import MediatorTargets import SwiftyMediatorlet vc = Mediator.viewController(of: ModuleAMediatorType.home(title: "Home"))復制代碼嗯,就是這么簡單。
如果只做簡單的模塊間通信,到這是足夠的了, 主要的就是2個協(xié)議。
5. 路由化及動態(tài)化
當然,有些時候我們需要做一些動態(tài)化的路由策略,比如做一下動態(tài)路由下發(fā)。我也對SwiftyMediator做了一些接口適配,使用方式如下:
當需要實現(xiàn)動態(tài)化的時候,不可避免的要去注冊,而且要實現(xiàn)協(xié)議中的枚舉初始化。雖然有些不便,但是在整體的接口收束度上還是挺不錯的。相比較注冊URL的方式來說,這些注冊就少很多了。
6. 模塊獲取App生命周期
鑒于目前系統(tǒng)有比較全面的生命周期通知定義,而且不需要在模塊中大量注冊url,所以這部分功能目前在考慮是否需要添加。
雖然代碼很簡單,實現(xiàn)也很簡單,但是跳出慣性思維,再去嘗試同樣需要很多思考。
SwiftyMediator,歡迎star。
其他使用方法見:
demo
參考資料:
WWDC - Protocol Witness Table
swift的witness table
URLNavigator
轉(zhuǎn)載于:https://juejin.im/post/5c43070e6fb9a049a5713435
總結(jié)
以上是生活随笔為你收集整理的另辟蹊径--极简Swifty路由的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: echart2文档(简单明白)
- 下一篇: 刻度如果数据比较大的情况下会溢出