JLRoutes原理剖析,使用举例

一.JLRoutes介绍

1.定义 JLRoutes本质可以理解为:保存一个全局的Map,key是url,value是对应的block,url和block都会常驻在内存中,当注册的url很多了,对内存的消耗也是很大的。当打开一个URL时,JLRoutes就可以遍历这个全局的map,通过url来执行对应的block。
image.png

根据流程图看一下创建代码

+ (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];
}

知识点补充

  1. 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。

你可能感兴趣的:(JLRoutes原理剖析,使用举例)