URLNavigator是Swift版本的Router。
Router的主要作用是解耦聚至。之前在各個ViewController
間跳轉(zhuǎn),需要import ViewController
爹梁,這樣就造成ViewController
之間的依賴搀别,也即耦合。通過router
不需要再import ViewController
执赡。所有的只要import router
镰踏,只依賴router
這一個類,router
里再去import
其他的ViewController
沙合,這樣奠伪,就達(dá)到我們說的解耦。
一個基本完善的router
首懈,我認(rèn)為應(yīng)該有下面幾個核心功能:
- 跳轉(zhuǎn)
ViewController
- 跳轉(zhuǎn)服務(wù)
- 回傳值
跳轉(zhuǎn)ViewController是基本功能绊率,這里包括跳轉(zhuǎn)的時(shí)候,傳入?yún)?shù)究履。
對于跳轉(zhuǎn)滤否,我們需要做到通過一個字符串,來跳轉(zhuǎn)到我們想要的頁面最仑,那么我們首先要做的是將字符串和對應(yīng)的頁面關(guān)聯(lián)起來藐俺,到時(shí)候炊甲,你給我這個字符串,我就知道你需要去哪個頁面欲芹。
在URLNavigator
里有一個注冊方法纤掸,就是將字符串和需要跳轉(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
里面做的事很簡單,就是用一個字典將字符串和和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)動作乓梨。
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ù),有時(shí)候辱志,我們并不想跳到一個頁面蝠筑,僅僅是想調(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)
}
這個是我假想的一個方法臣镣。實(shí)際有一個和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
}
回傳值,有時(shí)候鸽素,我們跳轉(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í)候,拿到字符串磨澡,解析出參數(shù)碗啄,找到相應(yīng)的閉包,將參數(shù)傳給閉包執(zhí)行稳摄,執(zhí)行閉包得到的ViewController
稚字,拿去跳轉(zhuǎn)。