讀URLNavigator源碼

URLNavigator是Swift版本的Router。

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

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

  • 跳轉(zhuǎn)ViewController
  • 跳轉(zhuǎn)服務(wù)
  • 回傳值

跳轉(zhuǎn)ViewController是基本功能,這里包括跳轉(zhuǎn)的時候,傳入?yún)?shù)。

對于跳轉(zhuǎn),我們需要做到通過一個字符串,來跳轉(zhuǎn)到我們想要的頁面,那么我們首先要做的是將字符串和對應(yīng)的頁面關(guān)聯(lián)起來,到時候,你給我這個字符串,我就知道你需要去哪個頁面。

URLNavigator里有一個注冊方法,就是將字符串和需要跳轉(zhuǎn)的ViewController關(guān)聯(lián)起來。

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

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

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

這樣不僅可以跳轉(zhuǎn)到關(guān)聯(lián)頁面,還能傳遞參數(shù)。
register里面做的事很簡單,就是用一個字典將字符串和和ViewController關(guān)聯(lián)起來。

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

將字符串作為字典的key,創(chuàng)建ViewController的閉包作為value,就這樣關(guān)聯(lián)了字符串和ViewController

在調(diào)用的時候,再根據(jù)字符串找到相應(yīng)的閉包,得到ViewController,執(zhí)行跳轉(zhuǎn)動作。

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,再執(zhí)行factory(url, match.values, context)。

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

然后

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

調(diào)用服務(wù),有時候,我們并不想跳到一個頁面,僅僅是想調(diào)用某個類里面的某個函數(shù)。

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

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

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

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

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

有一個保存閉包和字符串對應(yīng)關(guān)系的字典handlerFactories,不和register字典共用。
所以調(diào)用方法是

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

回傳值,有時候,我們跳轉(zhuǎn)到某個頁面,需要這個頁面執(zhí)行后,把相關(guān)結(jié)果返回。

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

總結(jié)一下:自己定義一個字符串規(guī)則,包含頁面信息和參數(shù)信息,然后將字符串和對應(yīng)的閉包關(guān)聯(lián)起來,閉包可以是創(chuàng)建相應(yīng)ViewController的操作,也可以是調(diào)用函數(shù)的操作,也可以是其他操作。在router通過字符串跳轉(zhuǎn)的時候,拿到字符串,解析出參數(shù),找到相應(yīng)的閉包,將參數(shù)傳給閉包執(zhí)行,執(zhí)行閉包得到的ViewController,拿去跳轉(zhuǎn)。

?著作權(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)容

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