前言:
現(xiàn)在有很多第三方路由庫从撼,例如:
1.JLRoute
2.MGJRouter
3.HHRouter
4.FFRouter
等等這些優(yōu)秀的第三方庫差不多都能滿足路由的基本功能
應(yīng)用:
以JLRoute為例:
先注冊一個路由
JLRoutes.global().addRoute("/ViewController1") { (param:[String : Any]) -> Bool in
let viewController1 = ViewController1.init()
pushClassStance.pushViewController(viewController1, animated: true)
return true
}
然后跳轉(zhuǎn)
let url:URL = URL.init(string: "XIAOGUO://ViewController1")!
JLRoutes.routeURL(url)
一個簡單的路由跳轉(zhuǎn)就實現(xiàn)了胆筒,當然如果是單純的跳轉(zhuǎn)到指定頁面還是比較好處理的。
那么這里就會延伸出兩個問題
1邻吞、如果頁面需要傳參該怎么做?
2葫男、ViewController需要提前注冊抱冷,如果沒有注冊的頁面就沒辦法做跳轉(zhuǎn),能否做動態(tài)注冊梢褐?
先看第一個問題旺遮,JLRoute其實已經(jīng)提供了帶參數(shù)的傳遞方式:
let url:URL = URL.init(string: "XIAOGUO://ViewController1/userName/xiaoguo/password/123456/isLogin/1")!
JLRoutes.routeURL(url)
那么我們?nèi)绾螌⒙酚傻膮?shù)與頁面的參數(shù)做對應(yīng)呢?
JLRoutes.global().addRoute("/ViewController1/userName/:userName/password/:password/isLogin/:isLogin") { (param:[String : Any]) -> Bool in
let viewController1 = ViewController1.init()
viewController1.userName = param["userName"] as! String
viewController1.password = Int(param["password"] as! String) ?? 0
viewController1.isLogin = (param["isLogin"] as! NSString).boolValue
pushClassStance.pushViewController(viewController1, animated: true)
return true
}
看起來似乎可以處理參數(shù)問題盈咳,仔細考慮一下如果參數(shù)沒有提前注冊好或者漏掉一些參數(shù)那還是無法實現(xiàn)正常傳參耿眉,能否實現(xiàn)動態(tài)傳參呢?
如果是swift類注冊路由鱼响,傳參我們可以利用反射來做類的屬性的映射:
JLRoutes.global().addRoute("/:ViewController") { (param:[String : Any]) -> Bool in
let vcName = param["ViewController"] as? String ?? ""
//根據(jù)vcName獲取對應(yīng)的控制器
if let clz = NSClassFromString("\(kCFBundle).\(vcName)") as? UIViewController.Type {
let vc:UIViewController = clz.init()
//反射控制器屬性
let vcM = Mirror(reflecting: vc)
//過濾參數(shù)關(guān)鍵字
let filterParam = param.filter({ (arg0) -> Bool in
let (key, _) = arg0
return key != "JLRoutePattern" && key != "JLRouteURL" && key != "JLRouteScheme" && key != "ViewController"
})
//找到對應(yīng)的控制器屬性并賦值
for (key,value) in filterParam {
for child in vcM.children {
if key == child.label {
//print("key:\(key),child.label:\(String(describing: child.label))")
vc.setValue(value, forKey: key)
}
}
}
pushClassStance.pushViewController(vc, animated: true)
return true
}
return false
}
發(fā)起跳轉(zhuǎn)統(tǒng)一用標準url傳參方式(鸣剪?&):
let url:URL = URL.init(string: "XIAOGUO://VC3?userName=xiaoguo&password=123456&isLogin=1")!
JLRoutes.routeURL(url)
這樣就完成動態(tài)傳參的問題。
這里會發(fā)現(xiàn)通過反射只能在swift頁面內(nèi)部之間跳轉(zhuǎn),如果跳轉(zhuǎn)的頁面是oc頁面則反射不到對應(yīng)的屬性筐骇,那要如何處理呢债鸡?
只能通過Runtime的class_copyPropertyList 或class_copyIvarList獲取類的屬性(swift屬性必須聲明為@objc賦予動態(tài)性)
改成class_copyPropertyList方式:
JLRoutes.global().addRoute("/:ViewController") { (param:[String : Any]) -> Bool in
let vcName = param["ViewController"] as? String ?? ""
//oc類
let ocClz = NSClassFromString("\(vcName)") as? UIViewController.Type
//swift類
let swfClz = NSClassFromString("\(kCFBundle).\(vcName)") as? UIViewController.Type
//根據(jù)vcName獲取對應(yīng)的類(oc/swift)
if let clz = ocClz ?? swfClz {
//過濾參數(shù)關(guān)鍵字
let filterParam = param.filter({ (arg0) -> Bool in
let (key, _) = arg0
return key != "JLRoutePattern" && key != "JLRouteURL" && key != "JLRouteScheme" && key != "ViewController"
})
let vc:UIViewController = clz.init()
//Runtime獲取類屬性
var count:UInt32 = 0
let propertyList = class_copyPropertyList(clz, &count)
//找到對應(yīng)的類屬性并賦值
for (key,value) in filterParam {
print("key:\(key),value:\(value)")
for i in 0..<numericCast(count) {
let property = property_getName((propertyList?[i])!);
let proper = String.init(cString: property)
if key == proper {
vc.setValue(value, forKey: key)
}
}
}
//釋放內(nèi)存
free(propertyList)
pushClassStance.pushViewController(vc, animated: true)
return true
}
return false
}
這樣就可以兼容oc頁面的傳參了