前言:
现在有很多第三方路由库,例如:
1.JLRoute
2.MGJRouter
3.HHRouter
4.FFRouter
等等这些优秀的第三方库差不多都能满足路由的基本功能
应用:
以JLRoute为例:
先注册一个路由
JLRoutes.global().addRoute("/ViewController1") { (param:[String : Any]) -> Bool in
let viewController1 = ViewController1.init()
pushClassStance.pushViewController(viewController1, animated: true)
return true
}
然后跳转
let url:URL = URL.init(string: "XIAOGUO://ViewController1")!
JLRoutes.routeURL(url)
一个简单的路由跳转就实现了,当然如果是单纯的跳转到指定页面还是比较好处理的。
那么这里就会延伸出两个问题
1、如果页面需要传参该怎么做?
2、ViewController需要提前注册,如果没有注册的页面就没办法做跳转,能否做动态注册?
先看第一个问题,JLRoute其实已经提供了带参数的传递方式:
let url:URL = URL.init(string: "XIAOGUO://ViewController1/userName/xiaoguo/password/123456/isLogin/1")!
JLRoutes.routeURL(url)
那么我们如何将路由的参数与页面的参数做对应呢?
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
}
看起来似乎可以处理参数问题,仔细考虑一下如果参数没有提前注册好或者漏掉一些参数那还是无法实现正常传参,能否实现动态传参呢?
如果是swift类注册路由,传参我们可以利用反射来做类的属性的映射:
JLRoutes.global().addRoute("/:ViewController") { (param:[String : Any]) -> Bool in
let vcName = param["ViewController"] as? String ?? ""
//根据vcName获取对应的控制器
if let clz = NSClassFromString("\(kCFBundle).\(vcName)") as? UIViewController.Type {
let vc:UIViewController = clz.init()
//反射控制器属性
let vcM = Mirror(reflecting: vc)
//過濾參數關鍵字
let filterParam = param.filter({ (arg0) -> Bool in
let (key, _) = arg0
return key != "JLRoutePattern" && key != "JLRouteURL" && key != "JLRouteScheme" && key != "ViewController"
})
//找到对应的控制器属性并赋值
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
}
发起跳转统一用标准url传参方式(?&):
let url:URL = URL.init(string: "XIAOGUO://VC3?userName=xiaoguo&password=123456&isLogin=1")!
JLRoutes.routeURL(url)
这样就完成动态传参的问题。
这里会发现通过反射只能在swift页面内部之间跳转,如果跳转的页面是oc页面则反射不到对应的属性,那要如何处理呢?
只能通过Runtime的class_copyPropertyList 或class_copyIvarList获取类的属性(swift属性必须声明为@objc赋予动态性)
改成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
//根据vcName获取对应的类(oc/swift)
if let clz = ocClz ?? swfClz {
//過濾參數關鍵字
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)
//找到对应的类属性并赋值
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)
}
}
}
//释放内存
free(propertyList)
pushClassStance.pushViewController(vc, animated: true)
return true
}
return false
}
这样就可以兼容oc页面的传参了
网友评论