讀URLNavigator源碼

桔子聽 2019-06-27 18:01:33 1313

URLNavigator是Swift版本的Router。

Router的主要作用是解耦。之前在各個ViewController間跳轉,需要import ViewController,這樣就造成ViewController之間的依賴,也即耦合。通過router不需要再import ViewController。所有的只要import router,只依賴router這一個類,router里再去import 其他的ViewController,這樣,就達到我們說的解耦。

一個基本完善的router,我認為應該有下面幾個核心功能:

  • 跳轉ViewController

  • 跳轉服務

  • 回傳值

跳轉ViewController是基本功能,這里包括跳轉的時候,傳入參數。

對于跳轉,我們需要做到通過一個字符串,來跳轉到我們想要的頁面,那么我們首先要做的是將字符串和對應的頁面關聯起來,到時候,你給我這個字符串,我就知道你需要去哪個頁面。

URLNavigator里有一個注冊方法,就是將字符串和需要跳轉的ViewController關聯起來。

navigator.register("navigator://user")?{?url,?values,?context?in
??????return?UserViewController()
????}

更進一步,可以在字符串里把需要傳遞的參數也帶上

navigator.register("navigator://user/")?{?url,?values,?context?in
??????guard?let?username?=?values["username"]?as??String?else?{?return?nil?}
??????return?UserViewController(navigator:?navigator,?username:?username)
????}

這樣不僅可以跳轉到關聯頁面,還能傳遞參數。
register里面做的事很簡單,就是用一個字典將字符串和和ViewController關聯起來。

public?typealias?URLPattern?=?String
private?var?viewControllerFactories?=?[URLPattern:?ViewControllerFactory]()
open?func?register(_?pattern:?URLPattern,?_?factory:[email protected]?ViewControllerFactory)?{
????self.viewControllerFactories[pattern]?=?factory
??}

將字符串作為字典的key,創建ViewController的閉包作為value,就這樣關聯了字符串和ViewController

在調用的時候,再根據字符串找到相應的閉包,得到ViewController,執行跳轉動作。

open?func?viewController(for?url:?URLConvertible,?context:?Any??=?nil)?->?UIViewController??{
????let?urlPatterns?=?Array(self.viewControllerFactories.keys)
????guard?let?match?=?self.matcher.match(url,?from:?urlPatterns)?else?{?return?nil?}
????guard?let?factory?=?self.viewControllerFactories[match.pattern]?else?{?return?nil?}
????return?factory(url,?match.values,?context)
??}

viewControllerFactories字典里拿到factory,再執行factory(url, match.values, context)

這里的guard let match = self.matcher.match(url, from: urlPatterns) else { return nil }是拿到url里的參數,這里面參數的傳入有一個自己定義的規則。URLMatcher.swift就是專門處理字符串的拆分,拿到參數。

然后

navigator.push("navigator://user/zhangsan")
navigator.present("navigator://user/zhangsan")

調用服務,有時候,我們并不想跳到一個頁面,僅僅是想調用某個類里面的某個函數。

navigator.register("navigator://user/")?{?url,?values,?context?in
??????guard?let?username?=?values["username"]?as??String?else?{?return?nil?}
??????return?UserViewController(navigator:?navigator,?username:?username)
????}

這個是上面的注冊代碼,我們只要修改一下就可以了,調用服務,其他的操作一樣

navigator.register("navigator://user/")?{?url,?values,?context?in
??????guard?let?username?=?values["username"]?as??String?else?{?return?nil?}
??????//獲取UserViewController對象?userVC,調用方法
????????userVC.callFuc(username:?username)
????}

這個是我假想的一個方法。實際有一個和register類似的方法

private?var?handlerFactories?=?[URLPattern:?URLOpenHandlerFactory]()
open?func?handle(_?pattern:?URLPattern,?_?factory:[email protected]?URLOpenHandlerFactory)?{
????self.handlerFactories[pattern]?=?factory
??}

有一個保存閉包和字符串對應關系的字典handlerFactories,不和register字典共用。
所以調用方法是

navigator.handle("navigator://user/")?{?(url,?values,?context)?->?Bool?in
??????guard?let?username?=?values["username"]?as??String?else?{?return?nil?}
??????//獲取UserViewController對象?userVC,調用方法
????????userVC.callFuc(username:?username)
??????return?true
????}

回傳值,有時候,我們跳轉到某個頁面,需要這個頁面執行后,把相關結果返回。

目前,URLNavigator還沒有第三個功能。

總結一下:自己定義一個字符串規則,包含頁面信息和參數信息,然后將字符串和對應的閉包關聯起來,閉包可以是創建相應ViewController的操作,也可以是調用函數的操作,也可以是其他操作。在router通過字符串跳轉的時候,拿到字符串,解析出參數,找到相應的閉包,將參數傳給閉包執行,執行閉包得到的ViewController,拿去跳轉。

广东26选5开奖结果查