來源:
URLNavigator是devxoul發(fā)布在github上的一個開源庫,他倉庫下面還包括了(Then, SwiftyImage, ReactorKit)等很有名的開源庫。
URLNavigator是什么:
devxoul 簡單的寫了一句話:Elegant URL Routing for Swift
其實就是優(yōu)雅的路由跳轉為了解耦模塊。
我們平時怎么做跳轉:
self.navigationController?.pushViewController(MineViewController(), animated: true)
這是我們平時的路由跳轉的方式,看上去沒什么不好的地方。其實我也覺得只要能完成項目都是好的,但是說句官方話:好處是移除 ViewController 中的依賴關系...
URLNavigator原理:
其實大多數(shù)的Router開源庫原理都差不多,1.解析URL。2.根據(jù)解析好的URL去跳轉,或是做其他的事情。
使用
使用起來也異常的簡單明了,首先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))
}
當我要跳轉到MineViewController我應該怎么做呢?重點來了 ↓↓↓↓↓↓↓
navigator.push("navigator://mine/abc")
// abc是我要傳遞給第二個頁面的參數(shù)
好了,URLNavigator的主要功能已經(jīng)演示完畢了,下面我們來看一個問題。
如果我傳遞過去的參數(shù)不止一個我該怎么辦????
解答:URLNavigator提供的有path函數(shù)在(URLMatcher)的里面
但是!我想要傳一個模型對象過去該怎么辦???
我看了一下源碼還真的無法做到,平常比如說我們在A頁面然后我們有個UserInfo類,當我們跳轉到B頁面要帶UserInfo的實例過去,那我們用URLNavigator應該怎么做呢?
我的想法:吧UserInfo實例轉化成JSON格式的字符串然后拼接在"navigator://mine/{json格式的字符串}"就可以了吧。
實驗:發(fā)現(xiàn)確實可以
又一個想法:當我B頁面拿到這個JSON格式的字符串總要換成模型吧,當然Decoable能幫我們解決,可是我們畢竟是為了解耦,swift又這么方便,如果我們有UserInfo實例,又有Dog實例,Person, User, Model等等都需要轉換,我們怎么樣寫一個函數(shù)就把所有的都實現(xiàn)呢?
實驗:泛型
<不要問我怎么不傳字典,本文只針對模型>
擴展:
OK,現(xiàn)在我們回到上面的第一個問題,怎么把一個model轉換為JSON格式的字符串.
- model遵守Codable協(xié)議
- 用JSONEncoder進行解析
定義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
}
}
我們使用關聯(lián)類型來匹配不同的模型實例,然后我們在每個需要model轉為JSON格式字符串的model里擴展一下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! 這下可以了我們來做個試驗:
let userinfo = UserInfo(name: "Hally", age: 2, avator: "333")
userinfo.valueString
//打印:navigator://mine/{"name":"Hally","age":2,"avator":"333"}
哦喲還不錯哦。
這個問題算是解決了,并且也用到了很swifty的方式,下面到第二個問題了,我們怎么在B頁面把傳遞過來的JSON格式字符串反推回model -> 泛型
怎么做?
// 因為JSON格式的字符串就是一個字符串,所以我們只要擴展一下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)
}
}
然后怎么使用嘞?
// 其實上面我已經(jīng)使用過了(NavigatorMap)類里
// userinfoString = "{\"name\":\"Hally\",\"age\":2,\"avator\":\"333\"}"
let userInfo = userinfoString.toObject(UserInfo.self)
// 最后得到userInfo的實例對象
最后我們就可以在B頁面愉快的使用userInfo了,這樣傳遞模型的擴展就完成了。僅供小白參考,大神請狠狠的指教。
UseageURLNavigator 代碼地址
感謝@故事的小黃瓜提供的泛型思路