背景
项目中有rn 和h5 的交互的各种往来,维护这个项目的时候发现了有广泛应用的在项目中的router。简单研究了一下,虽然还没有来得及对比美团,蘑菇街,等router 鼻祖级别的路由协议,也没有看掘金上班两股力量的争论,研究东西,总不会太坏
表面应用
表层的api 很简单
//注册
- (void)map:(NSString *)route toControllerClass:(Class)controllerClass;
- (void)map:(NSString *)route toBlock:(JFRouterBlock)block;
//取controller
- (UIViewController *)matchController:(NSString *)route;
- (JFRouterBlock)matchBlock:(NSString *)route;
//直接
- (id)callBlock:(NSString *)route;
//判断routeType
- (JFRouteType)canRoute:(NSString *)route;
1 注册 是把对应的controller 和 router string 绑定在一起
2 取controller 用router 取出来 对应的controller 以达到不用import 的目的
3 block , 这个 我之前也是不理解的,就是用于给目标的controller set 初始参数
4 canroute,判断router 是否有效
这里说一下有意识的点,就是我看了下其他的router ,可以通过router 来传参数。表示没有看动为啥要这么做,可能为了,更好的和其他的语言编写的业务沟通吧
调用方法 block
[[JFRouter shared] map:@"hello" toBlock:^id(NSDictionary *params,id aCallback) {
id viewController = nil;
Class c = NSClassFromString(@"RouterTwoViewController");
viewController = [[c alloc] init];
[(UIViewController *)viewController setParams:params];
return viewController;
}];
这里面的block 通过setParams 来传递参数。params 是通过runtime 给每个vc 加的属性。
JFRouterBlock block = [[JFRouter shared] matchBlock:@"hello"];
UIViewController *v = block(@{@"title_jf":@"blocktitle",@"subTitle":@"hello world"},nil);
[self.navigationController pushViewController:v animated:YES];
这里 通过block 传参,来对param set。这也是我个人最绕的地方,后来发现,block 传值一般都是 传递初始化的值, router 对应的不是controller 而是block。这样的理解好像能好过一些
调用方法 正常调用
UIViewController *v = [[JFRouter shared] matchController:@"hello"];
[self.navigationController pushViewController:v animated:YES];
直接通过router 对应的controller 来调用
Class c = NSClassFromString(@"RouterTwoViewController");
[[JFRouter shared] map:@"hello" toControllerClass:c];
这个时候,设置parame 的方法就简单很多,直接通过rumtime 设置的字典传值,通过kvc 取。
这一切的目的为了少 引入.h文件,或者其他的模块的文件,起到解耦的目的。
这里不同技术经历的人,对解耦的理解是不一样。因为这里涉及到软件的开始经历和自己的理解。我个人的理解是根据业务的结构来区分代码的耦合度,比如有个基金模块,内部的逻辑相对理财独立,交集的点很有限,那么有交集的地方,就是路由开始使用的时候来,或者 比如你的项目中有rn 代码 ,h5 相互的调用,有个路由就很方便,没有,可能如果项目没有美团,蘑菇街那么大 可能也ok。
所以我理解到这里,我发现,如果你的项目中用到了路由,说明你的项目已经很大,或者就是为了用而用。
原理分析
block
当注册的时候
- (void)map:(NSString *)route toBlock:(JFRouterBlock)block{
NSMutableDictionary *subRoutes = [self subRoutesToRoute:route];
subRoutes[@"_"] = [block copy];
}
- (NSMutableDictionary *)subRoutesToRoute:(NSString *)route{
NSString *host = [self hostFromRoute:route];
NSMutableDictionary *dic = self.routes[host];
if (dic == nil) {
dic = [NSMutableDictionary dictionary];
self.routes[host] = dic;
}
return dic;
}
当调用 matchBlock 的时候
上边的字典的内容变成了
{
"_" = "<__NSGlobalBlock__: 0x103be9928>";
}
当block()中传递参数的时候, map 的block 会被调用,这样,就实现了viewController 在生成的时候 被设置参数的目的。
这点可能要对block理解的比较熟悉,如果习惯了block 的用法,而忘记了block 的原理,可能这个点又能让我们回顾一下block 的本质含义。
block 中回调的时候会发现
[[JFRouter shared] map:@"hello" toBlock:^id(NSDictionary *params,id aCallback) {
id viewController = nil;
Class c = NSClassFromString(@"RouterTwoViewController");
viewController = [[c alloc] init];
[(UIViewController *)viewController setParams:params];
return viewController;
}];
=================================params=====output======================================
{
subTitle = "hello world";
"title_jf" = blocktitle;
}
你要的参数
具体应用和争议
two 可能不需要了.h文件,这个是他最大的争论问题,如果仅仅的iOS 内部,那么这个路由,真的很让你感觉鸡肋,OC 的一大特点就是有.h 文件,让对外声明可以很好的区分。但是如果你是swift 开发,rn 开发, h5 开发,和你的项目有千丝万缕的联系,如果这个时候有个人router , 你可能就能理解了。 不过这个度还是要把握好,业务需求
完结
好久没有更新,关于路由已经是去年比较话题了,可我居然是不知道的状态,差点和时代脱节了。
最近最热的区块链,本人突然感觉兴趣来了,可能后期写一些关于智能合约的开发文章。本质估计都不会差的太远。你我共勉
这里有一些文章还没有来得及看
http://limboy.me/tech/2016/03/10/mgj-components.html 蘑菇街的实现,虽然蘑菇街不是一线的互联网公司,但是关于路由我印象中他是第一个提出来的。
不管是不是有争议,能提出新见解就是进步,值得学习。