一.JLRoutes介绍
1.定义 JLRoutes本质可以理解为:保存一个全局的Map,key是url,value是对应的block,url和block都会常驻在内存中,当注册的url很多了,对内存的消耗也是很大的。当打开一个URL时,JLRoutes就可以遍历这个全局的map,通过url来执行对应的block。
根据流程图看一下创建代码
+ (instancetype)routesForScheme:(NSString *)scheme
{
JLRoutes *routesController = nil;
static dispatch_once_t onceToken;
//全局之创建一个MAP
dispatch_once(&onceToken, ^{
JLRGlobal_routeControllersMap = [[NSMutableDictionary alloc] init];
});
//用scheme作为key,然后JLRoutes作为value值,JLRoutes中有可变数组来存储不同的URL生成的模型对象,JLRRouteDefinition;
if (!JLRGlobal_routeControllersMap[scheme]) {
routesController = [[self alloc] init];
routesController.scheme = scheme;
JLRGlobal_routeControllersMap[scheme] = routesController;
}
routesController = JLRGlobal_routeControllersMap[scheme];
return routesController;
}
2.各个类的作用
1、JLRRouteRequest提供输入URL的分解,分解为scheme、path、param和fragment等(为后续生成response做准备) 2、JLRRouteResponse
则是结果的封装,包括匹配的参数(就是block返回的字典值)、是否匹配(输入的URL会循环匹配之前注册好的URL,如果匹配上返回YES,就会执行block)等内容
3.JLRRouteDefinition用固有的规则初始化,去计算
JLRouteRequest是否匹配自己的规则并输出(个人理解为模型数据对象,没个URL会生成一个JLRRouteDefinition,存在数组中) 4.JLRoutes
进行Route的管理、调度、优先级管理(咱们可以直接使用的方法都在里边,做各个类的管理,调度)
5.JLRParsingUtilities 主要提供根据传入的匹配链接生成对应的合规的URI(仅仅将可选类型,拆解,例子如下)
/path/:thing/(/a)(/b)(/c)
create the following paths:
/path/:thing/a/b/c
/path/:thing/a/b
/path/:thing/a/c
/path/:thing/b/c
/path/:thing/a
/path/:thing/b
/path/:thing/c
*/
6.JLRRouteHandler 工具辅助类,不参与主逻辑
总结:JLRoutes作为入口,封装对外的函数;JLRRouteRequest负责拆解;JLRRouteResponse生成的结果;JLRRouteDefinition就是一个数据模型,每一个URL都会生成一个JLRRouteDefinition,在JLRRouteDefinition中根据JLRouteRequest生成一个JLRRouteResponse。
二.使用场景
deep link:通过 Custom URL Scheme 由外部跳转到 app,比如推送跳转,app 间跳转。
app 内部路由跳转:使用中介者模式对 controller 进行解耦。
1.通过 Custom URL Scheme 由外部跳转到 app,比如推送跳转,app 间跳转
(1)didFinishLaunchingWithOptions中注册
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[JLRoutes globalRoutes] addRoute:@"取url内容值的标识"handler:^BOOL(NSDictionary * _Nonnull parameters) {returnYES; // 一旦匹配,立即返回 YES}];
}
(2)接收处理
// iOS 9.0前方法
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
NSLog(@"Calling Application Bundle ID: %@", sourceApplication);
NSLog(@"URL scheme: %@", [url scheme]);
NSLog(@"URL query: %@", [url query]);
// 从浏览器打开时候会自动全部转成小写,而从应用内调用的话大小写不会变化
// 为了方便判断所以统一转成小写来判断
NSString *urlSchemeStr = [[url scheme] lowercaseString]; // url scheme 转换为小写的字符串
NSLog(@"urlSchemeStr: %@",urlSchemeStr);
if ([urlSchemeStr isEqualToString:@"jlrouteschemeone"]) {
// 要和 info.plist 的 URL types 里面的一致
return [[JLRoutes routesForScheme:@"JLRouteSchemeOne"]routeURL:url];
} else if ([urlSchemeStr isEqualToString:@"jlrouteschemetwo"]) {
// 要和 info.plist 的 URL types 里面的一致
return [[JLRoutes routesForScheme:@"JLRouteSchemeTwo"]routeURL:url];
}
return YES;
}
// iOS 9.0后方法
- (BOOL)application:(UIApplication *)app openURL:(nonnull NSURL *)url options:(nonnull NSDictionary *)options {
NSLog(@"options: %@", options);
NSLog(@"Calling Application Bundle ID: %@", [options objectForKey:@"UIApplicationOpenURLOptionsSourceApplicationKey"]);
NSLog(@"URL scheme: %@", [url scheme]);
NSLog(@"URL host : %@", [url host]);
NSLog(@"URL query: %@", [url query]);
// 从浏览器打开时候会自动全部转成小写,而从应用内调用的话大小写不会变化
// 为了方便判断所以统一转成小写来判断
NSString *urlSchemeStr = [[url scheme] lowercaseString]; // url scheme 转换为小写的字符串
NSLog(@"urlSchemeStr: %@",urlSchemeStr);
if ([urlSchemeStr isEqualToString:@"jlrouteschemeone"]) {
// 要和 info.plist 的 URL types 里面的一致
return [[JLRoutes routesForScheme:@"JLRouteSchemeOne"]routeURL:url];
} else if ([urlSchemeStr isEqualToString:@"jlrouteschemetwo"]) {
// 要和 info.plist 的 URL types 里面的一致
return [[JLRoutes routesForScheme:@"JLRouteSchemeTwo"]routeURL:url];
}
return YES;
}
app 内部路由跳转:使用中介者模式对 controller 进行解耦
具体根据demo讲解。demo中将所有主要函数均作了注释,可根据断点走一下全流程。
2.JLRoutes使用举例
(1)注册一个tabbar
-(UITabBarController*)setTabBarControllerRoutes:(UITabBarController*)tab{
tabControllerVC =[[BaseTabBarViewController alloc]init];
[[UITabBarItem appearance]setTitleTextAttributes:@{NSFontAttributeName:FONTS(@"PingFang-SC-Medium", 11),NSForegroundColorAttributeName:UIColorFromRGB(0x7e7674)} forState:UIControlStateNormal];
[[UITabBarItem appearance]setTitleTextAttributes:@{NSFontAttributeName:FONTS(@"PingFang-SC-Medium", 11),NSForegroundColorAttributeName:UIColorFromRGB(0xff5b40)} forState:UIControlStateSelected];
//Tabbar规则 注册
[[JLRoutes globalRoutes]addRoute :@"/Tabbar/:tabVC1/:tabVC2/:tabVC3" handler:^BOOL(NSDictionary * _Nonnull parameters) {
tabControllerVC.viewControllers = @[
[self viewControllerWithTitle:@"首页" image:[UIImage imageNamed:@"tab_home"] selectImage:[UIImage imageNamed:@"tab_home_select"] VC:[[NSClassFromString(parameters[@"tabVC1"]) alloc] init]],
[self viewControllerWithTitle:@"咨询" image:[UIImage imageNamed:@"tab_shequ"] selectImage:[UIImage imageNamed:@"tab_shequ_select"] VC:[[NSClassFromString(parameters[@"tabVC2"]) alloc] init]],
[self viewControllerWithTitle:@"我的" image:[UIImage imageNamed:@"tab_person"] selectImage:[UIImage imageNamed:@"tab_person_select"] VC:[[NSClassFromString(parameters[@"tabVC3"]) alloc] init]]
];
return YES;
}];
//调用
NSURL *viewUserURL = [NSURL URLWithString:@"TESTDEMO://Tabbar/HomeViewController/SKCommunityHomeViewController/PersonViewController"];
[JLRoutes routeURL:viewUserURL];
return tabControllerVC;
}
(2)导航控制器push使用和一些拓展函数,仅仅简单使用
//注册push路由规则
-(void)setNavigationPushRegular{
// navigation Push规则
[[JLRoutes globalRoutes]addRoute:@"/NaviPush/:controller" handler:^BOOL(NSDictionary * _Nonnull parameters) {
UIViewController *currentVc = [self currentViewController];
UIViewController *v = [[NSClassFromString(parameters[@"controller"]) alloc] init];
[self paramToVc:v param:parameters];
[currentVc.navigationController pushViewController:v animated:YES];
return YES;
}];
}
//设置导航和tabbarcontroller
-(UINavigationController *) viewControllerWithTitle:(NSString *) title image:(UIImage *)image selectImage:(UIImage *)selectImage VC:(UIViewController *)VC{
VC.tabBarItem.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
VC.tabBarItem.selectedImage = [selectImage imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
VC.title = [NSString stringWithFormat:@"%@",title];
VC.tabBarItem.title = title;
XJMNavigationController *nav = [[XJMNavigationController alloc] initWithRootViewController:VC];
return nav;
}
// runtime将参数传递至需要跳转的控制器
-(void)paramToVc:(UIViewController *) v param:(NSDictionary *)parameters{
unsigned int outCount = 0;
objc_property_t * properties = class_copyPropertyList(v.class , &outCount);
for (int i = 0; i < outCount; i++) {
objc_property_t property = properties[i];
NSString *key = [NSString stringWithUTF8String:property_getName(property)];
NSString *param = parameters[key];
if (param != nil) {
[v setValue:param forKey:key];
}
}
}
/**
* 获取当前控制器
*/
-(UIViewController *)currentViewController{
UIViewController * currVC = nil;
UIViewController * Rootvc = [UIApplication sharedApplication].keyWindow.rootViewController ;
do {
if ([Rootvc isKindOfClass:[UINavigationController class]]) {
UINavigationController * nav = (UINavigationController *)Rootvc;
UIViewController * v = [nav.viewControllers lastObject];
currVC = v;
Rootvc = v.presentedViewController;
continue;
}else if([Rootvc isKindOfClass:[UITabBarController class]]){
UITabBarController * tabVC = (UITabBarController *)Rootvc;
currVC = tabVC;
Rootvc = [tabVC.viewControllers objectAtIndex:tabVC.selectedIndex];
continue;
}
} while (Rootvc!=nil);
return currVC;
}
跳转就可以直接
//跳转页
-(void)jumpConStr:(NSString*)jumpStr{
NSURL *viewUserURL = [NSURL URLWithString:jumpStr];
[JLRoutes routeURL:viewUserURL];
}
知识点补充
- scheme是什么https://www.....中https就是scheme
2.(1) setValuesForKeysWithDictionary 一般用在KVC赋值的时候,直接通过字典给模型数据赋值
PersonModel.h
@property (nonatomic,copy)NSString *name;
@property (nonatomic,copy)NSString *sex;
@property (nonatomic,copy)NSString *age;
用 NSDictionary *dic = @{@"name":@"张三",@"sex":@"男",@"age":@"22"}给model赋值;
PersonModel *person =[[PersonModel alloc]init];
[person setValuesForKeysWithDictionary:dic];
注:如果字典中模型中不存在的对象需要容错处理
在.m文件中实现
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
}
(2)addEntriesFromDictionary是NSMutableDictionary的方法,合并两个字典,如果KEY相同,第二个会将第一个覆盖。
附件会上传做注释的demo。