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