JMRouter
一個輕量級,純Swift,協(xié)議化的路由控件,使用demo
要求
- iOS 8.0+
- Swift 5.0+
- YYBlog
安裝
pod 'JMRouter'
使用
- 自定義一個enum,實現(xiàn)JMRoutePage協(xié)議,每個case,表示該controller的唯一路徑
enum Page: String, JMRoutePage {
case home //key和約定的字符串一致
case vc1
case vc2 = "nibVc" //key和約定的字符串不一致時
}
- 想要一個controller支持路由跳轉(zhuǎn),需要實現(xiàn)JMRoutable協(xié)議,比如
extension HomeController: JMRoutable {
static var routePage: JMRoutePage {
return Page.home
}
static func routePageCreated(with url: String?,
parameters: [String: String]?,
object: Any?) -> UIViewController? {
return UIStoryboard(name: "Main", bundle: nil)
.instantiateInitialViewController()
}
}
- 可以使用下面2種方式跳轉(zhuǎn),可以帶額外參數(shù),并提供跳轉(zhuǎn)完成回調(diào)
/// 應(yīng)用內(nèi)使用枚舉方式跳轉(zhuǎn)更方便
JMRouter.goto(Page.home, from: self, object: UIColor.random) { resrult, _ in
YYHud.showTip(resrult ? "操作成功" : "操作失敗")
}
/// 使用url跳轉(zhuǎn)
JMRouter.routing(with: "scheme1://page/home?title="地圖") { resrult, _ in
YYHud.showTip(resrult ? "操作成功" : "操作失敗")
}
url類似下面這種格式,lastPathComponent為界面,可以帶參數(shù)
/// scheme1://page/map?title="地圖"
routing完整定義如下
/// 通過url 來跳轉(zhuǎn)對應(yīng)頁面, 或執(zhí)行某個action
///
/// - Parameters:
/// - urlString: url字符串
/// - object: 額外的參數(shù)
/// - vc: 優(yōu)先使用傳入的controller來執(zhí)行跳轉(zhuǎn)或action,否則會自動尋找當前的controller
/// - completion: routing完成后的回調(diào)(有動畫會異步),Bool同return的返回值
/// - Returns: 如果找到了對應(yīng)的page并跳轉(zhuǎn)成功,或執(zhí)行了對應(yīng)action,返回true
@discardableResult
public static func routing(with urlString: String,
object: Any? = nil,
from vc: UIViewController? = nil,
completion: Completion? = nil) -> Bool
- 在使用前需要調(diào)用一次路由注冊
static func setup(with appDelegate: UIApplicationDelegate,
schemes: [String],
pageHost: String = "page")
demo中更為詳細的例子,使用前可以先看看
更詳細的說明
設(shè)計思路
分別取url的
- scheme:表示支持的協(xié)議,可以配置多個
- host:表示執(zhí)行操作的類型,默認是page,之前還支持action,不過發(fā)現(xiàn)不好單獨提取出來,需要自己支持吧
- lastPathComponent:表示執(zhí)行的具體操作,比如跳轉(zhuǎn)到地圖頁
這些配置在每個項目中可能都有自己的規(guī)則,所以可以根據(jù)需求自行調(diào)整??
scheme和host定義在JMRouter.swift文件中,通過setup參數(shù)初始化
/// 支持的schemes
public static private(set) var schemes = [""]
public static private(set) var pageHost = "page"
lastPathComponent的Page部分在自己工程中定義,使用枚舉
/// 聲明哪些controller支持路由跳轉(zhuǎn)
enum Page: String, JMRoutePage {
case home
case vc1 //key和約定的字符串一致時
case vc2 = "nibVc" //key和約定的字符串不一致時
}
對于一些UI層次結(jié)構(gòu)比較特殊的項目
還有一個地方可能需要注意
JMRouter+Page.swift中goto函數(shù)里用來跳轉(zhuǎn)的vc,優(yōu)先使用傳入的vc,否則使用app top
/// 通過枚舉來跳轉(zhuǎn)對應(yīng)頁面
@discardableResult
static func goto(_ page: JMRoutePage,
url: String? = nil,
parameters: [String : String]? = nil,
object: Any? = nil,
from vc: UIViewController? = nil,
completion: Completion? = nil) -> UIViewController? {
。。。
/// 優(yōu)先使用傳入的vc,否則使用app top
guard let finalViewController = vc ?? UIViewController.appTopVC else {
return nil
}
。。。
}
路由映射
JMRouter.setup方法內(nèi)部會調(diào)用registerPathMap,遍歷主工程中所有類,判斷是否實現(xiàn)JMRoutable協(xié)議來自動注冊映射關(guān)系,可能會有點耗時。根據(jù)我們自己項目測試來看,大概幾W個類,1秒內(nèi)完成,所有看情況這步可以優(yōu)化。。
/// 遍歷所有的類,檢測是否實現(xiàn)Routable,存入字典作為映射表,使用Router前必須先調(diào)用
static func registerPathMap(with appDelegate: UIApplicationDelegate) {
var count: UInt32 = 0
guard let image = class_getImageName(object_getClass(appDelegate)),
let classes = objc_copyClassNamesForImage(image, &count) else {
print("JMRouter registerPathMap failed!!!!!!!!!!!!!!!!!!")
return
}
for i in 0 ..< Int(count) {
if let clsName = String(cString: classes[i], encoding: .utf8)?.components(separatedBy: ".").last {
if let cls = clsName.toClass() as? JMRoutable.Type {
pagePathMap.updateValue(clsName, forKey: cls.routePage.rawValue)
}
}
}
}