讀URLNavigator源碼

URLNavigator是Swift版本的Router。

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

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

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

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

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

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

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

更進(jìn)一步,可以在字符串里把需要傳遞的參數(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里面做的事很簡單,就是用一個(gè)字典將字符串和和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)用的時(shí)候,再根據(jù)字符串找到相應(yīng)的閉包,得到ViewController,執(zhí)行跳轉(zhuǎn)動(dòng)作。

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ù)的傳入有一個(gè)自己定義的規(guī)則。URLMatcher.swift就是專門處理字符串的拆分,拿到參數(shù)。

然后

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

調(diào)用服務(wù),有時(shí)候,我們并不想跳到一個(gè)頁面,僅僅是想調(diào)用某個(gè)類里面的某個(gè)函數(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)
    }

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

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

這個(gè)是我假想的一個(gè)方法。實(shí)際有一個(gè)和register類似的方法

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

有一個(gè)保存閉包和字符串對(duì)應(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對(duì)象 userVC,調(diào)用方法
        userVC.callFuc(username: username)
      return true
    }

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

目前,URLNavigator還沒有第三個(gè)功能。

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

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