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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容

  • 原文链接:https://github.com/halfrost/Halfrost-Field/blob/mast...
    hament阅读 5,638评论 1 31
  • 介绍 : JLRoutes是一个调用极少代码 , 可以很方便的处理不同URL schemes以及解析它们的参数,并...
    CoderLF阅读 1,621评论 0 3
  • 介绍 : JLRoutes是一个调用极少代码 , 可以很方便的处理不同URL schemes以及解析它们的参数,并...
    一支烟一只猿阅读 11,445评论 3 17
  • 1.复合系统中,它的各种构成要素之间保持着一定程度的独立性。这样一来,从系统中移除某个要素(这将降低系统的复杂性)...
    gqyjlu阅读 394评论 0 1
  • 我在无边的荒野 洒下一颗颗种子 我从来不看望它们 雨水会滋润它 蚯蚓会陪伴它 我只是静静地,静静地 等着,等到某一...
    崇文路2号阅读 219评论 0 0