美文网首页iOS-源码专题
JLRoutes原理剖析,使用举例

JLRoutes原理剖析,使用举例

作者: RainyHand | 来源:发表于2018-10-25 11:48 被阅读60次

    一.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<NSString*,id> * _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<UIApplicationOpenURLOptionsKey,id> *)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<NSString *,NSString *> * _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<NSString *,NSString *> * _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<NSString *,NSString *> *)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原理剖析,使用举例

        本文链接:https://www.haomeiwen.com/subject/qluqtqtx.html