來源:
URLNavigator是devxoul發(fā)布在github上的一個(gè)開源庫,他倉庫下面還包括了(Then, SwiftyImage, ReactorKit)等很有名的開源庫。
URLNavigator是什么:
devxoul 簡(jiǎn)單的寫了一句話:Elegant URL Routing for Swift
其實(shí)就是優(yōu)雅的路由跳轉(zhuǎn)為了解耦模塊良瞧。
我們平時(shí)怎么做跳轉(zhuǎn):
self.navigationController?.pushViewController(MineViewController(), animated: true)
這是我們平時(shí)的路由跳轉(zhuǎn)的方式敷钾,看上去沒什么不好的地方躺孝。其實(shí)我也覺得只要能完成項(xiàng)目都是好的,但是說句官方話:好處是移除 ViewController 中的依賴關(guān)系...
URLNavigator原理:
其實(shí)大多數(shù)的Router開源庫原理都差不多,1.解析URL。2.根據(jù)解析好的URL去跳轉(zhuǎn)跃赚,或是做其他的事情。
使用
使用起來也異常的簡(jiǎn)單明了性湿,首先pod...這就不說了纬傲。
Appdelegate.swift
private var navigator: NavigatorType?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let navigator = Navigator()
NavigatorMap.initialize(navigator: navigator)
}
NavigatorMap.swift
navigator.register("navigator://mine/<mine>") { url , values, context in
guard let userinfoString = values["mine"] as? String else { return nil }
return MineViewController(navigator: navigator, userInfo: userinfoString.toObject(UserInfo.self))
}
當(dāng)我要跳轉(zhuǎn)到MineViewController我應(yīng)該怎么做呢满败?重點(diǎn)來了 ↓↓↓↓↓↓↓
navigator.push("navigator://mine/abc")
// abc是我要傳遞給第二個(gè)頁面的參數(shù)
好了,URLNavigator的主要功能已經(jīng)演示完畢了叹括,下面我們來看一個(gè)問題葫录。
如果我傳遞過去的參數(shù)不止一個(gè)我該怎么辦?领猾??骇扇?
解答:URLNavigator提供的有path函數(shù)在(URLMatcher)的里面
但是摔竿!我想要傳一個(gè)模型對(duì)象過去該怎么辦?少孝?继低?
我看了一下源碼還真的無法做到,平常比如說我們?cè)贏頁面然后我們有個(gè)UserInfo類稍走,當(dāng)我們跳轉(zhuǎn)到B頁面要帶UserInfo的實(shí)例過去袁翁,那我們用URLNavigator應(yīng)該怎么做呢?
我的想法:吧UserInfo實(shí)例轉(zhuǎn)化成JSON格式的字符串然后拼接在"navigator://mine/{json格式的字符串}"就可以了吧婿脸。
實(shí)驗(yàn):發(fā)現(xiàn)確實(shí)可以
又一個(gè)想法:當(dāng)我B頁面拿到這個(gè)JSON格式的字符串總要換成模型吧粱胜,當(dāng)然Decoable能幫我們解決,可是我們畢竟是為了解耦狐树,swift又這么方便焙压,如果我們有UserInfo實(shí)例,又有Dog實(shí)例抑钟,Person, User, Model等等都需要轉(zhuǎn)換涯曲,我們?cè)趺礃訉懸粋€(gè)函數(shù)就把所有的都實(shí)現(xiàn)呢?
實(shí)驗(yàn):泛型
<不要問我怎么不傳字典,本文只針對(duì)模型>
擴(kuò)展:
OK在塔,現(xiàn)在我們回到上面的第一個(gè)問題幻件,怎么把一個(gè)model轉(zhuǎn)換為JSON格式的字符串.
- model遵守Codable協(xié)議
- 用JSONEncoder進(jìn)行解析
定義ConvertToStringable協(xié)議
protocol ConvertToStringable {
associatedtype Result: Codable
var valueString: String { get }
}
extension ConvertToStringable {
func toString(result: Result) -> String {
let data = try? JSONEncoder().encode(result)
guard let da = data else { return "" }
guard let st = String.init(data: da, encoding: .utf8) else { return "" }
return st
}
}
我們使用關(guān)聯(lián)類型來匹配不同的模型實(shí)例,然后我們?cè)诿總€(gè)需要model轉(zhuǎn)為JSON格式字符串的model里擴(kuò)展一下model:
struct UserInfo: Codable {
var name: String
var age: Int
var avator: String
}
extension UserInfo: ConvertToStringable {
typealias Result = UserInfo
var valueString: String { return toString(result: self) }
}
OK! 這下可以了我們來做個(gè)試驗(yàn):
let userinfo = UserInfo(name: "Hally", age: 2, avator: "333")
userinfo.valueString
//打印:navigator://mine/{"name":"Hally","age":2,"avator":"333"}
哦喲還不錯(cuò)哦蛔溃。
這個(gè)問題算是解決了绰沥,并且也用到了很swifty的方式,下面到第二個(gè)問題了城榛,我們?cè)趺丛贐頁面把傳遞過來的JSON格式字符串反推回model -> 泛型
怎么做揪利?
// 因?yàn)镴SON格式的字符串就是一個(gè)字符串,所以我們只要擴(kuò)展一下String就OK啦狠持。
extension String {
func toObject<T>(_ : T.Type) -> T? where T: Codable {
guard let data = self.data(using: .utf8) else { return nil }
return try? JSONDecoder().decode(T.self, from: data)
}
}
然后怎么使用嘞疟位?
// 其實(shí)上面我已經(jīng)使用過了(NavigatorMap)類里
// userinfoString = "{\"name\":\"Hally\",\"age\":2,\"avator\":\"333\"}"
let userInfo = userinfoString.toObject(UserInfo.self)
// 最后得到userInfo的實(shí)例對(duì)象
最后我們就可以在B頁面愉快的使用userInfo了,這樣傳遞模型的擴(kuò)展就完成了喘垂。僅供小白參考甜刻,大神請(qǐng)狠狠的指教绍撞。
UseageURLNavigator 代碼地址
感謝@故事的小黃瓜提供的泛型思路