简介
大约6个月前,笔者写了一个基于url-block的路由跳转框架,命名为WSRouter。这是一个轻量级框架,仅包含4个.m文件共400多行代码。虽然这个框架很轻,但并不代表其功能不完备,相反,这个框架的功能完全可以应付我们日常的开发需要。无论是对于项目使用还是学习参考,WSRouter都是一个不错的选择。
目前路由跳转方案有很多,大致分为4中:基于URL(url-controller、url-block)的方案、基于target-action的方案、protocol-class方案。本文所说的WSRouter是基于url-block的跳转方案。本文不对这些方案的优缺点进行对比,仅对WSRouter的基本功能和实现做一些简介,欢迎大家使用或star。
原理
基于URL-Controller的路由跳转本质上是有一个路由中介者管理着这些ViewController与URL的映射关系。每一个ViewController都有一个与之对应的URL。每添加一个ViewController我们都要注册一个能够唯一标识这个ViewController的URL到映射表中。如果是基于URL-block的方案,这个映射表中保存的是url-block的关系。当通过URL执行页面转场时,我们通过解析URL中的scheme、host、path。把这3者拼接成scheme://host/path的形式去注册表中查找对应的block或controller(如果是url-block关系,则这个block会返回一个controller)。然后解析URL中的query参数,用query参数配置这个ViewController对象。如果你对URL中的scheme、host、path、query等URL的各个部分不甚了解,下面的例子可以帮助你:
1 2 3 4 5 6 7
| NSURL *url = [NSURL URLWithString:@"ws://www.ws.com/first?uid=999&bid=666"]; id query = url.query; id scheme = url.scheme; id host = url.host; id path = url.path; id absString = url.absoluteString; id absUrl = url.absoluteURL;
|
使用
下面的例子中,先在+(void)load方法中注册了url和block的映射关系。然后调用transferFromViewController:toURL:
方法执行跳转。需要注意的是,我们在block的实现中创建了一个对应的控制器实例,然后用URL.query对控制器进行配置。通常,我们将需要传递个目的控制器的参数都拼接到URL.query中。
push转场
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #import "WSRouter.h" + (void)load { [self registerRouter]; }
+ (void)registerRouter { NSURL *url = [NSURL URLWithString:@"ws://www.ws.com/first"];
[WSRouter registerRouterWithPrefixURL:url handler:^UIViewController *(NSURL *URL, UIViewController *sourceViewController) {
WSPushedViewController *destViewController = [[WSPushedViewController alloc] init];
[WSRouter transferViewController:destViewController fromViewController:sourceViewController transition:WSTransitionPush]; destViewController.params = [NSString ws_parameterFromURLQuery:URL.query]; return destViewController; }]; }
[WSRouter transferFromViewController:self toURL:[NSURL URLWithString:@"WS://www.ws.com/first?uid=666"]];
|
带回调的转场
还是上面那个例子,有时候我们从目的控制器返回到上一个控制器时,需要执行某些回调,我们仅需要把上例的transferFromViewController:toURL:
换成transferFromViewController:toURL:viewWillDisappearCallBack:
。这样在页面退出是即可执行回调通知上一个控制器执行一些操作。此外除了viewWillDisappearCallBack
之外,WSRouter还支持viewDidDisappearCallBack
。其实现使用了Method swizzling。
1 2 3 4 5
| [WSRouter transferFromViewController:self toURL:[NSURL URLWithString:@"WS://www.ws.com/first?uid=666"] viewWillDisappearCallBack:^(UIViewController *destViewController, id callbackData) { NSLog(@"%@",callbackData); }];
|
modal转场
如果需要以modal的方式转场,那么仅需要在注册的block中把transition改为WSTransitionPresent即可。如下:
1 2 3 4 5 6 7 8 9 10
| + (void)registerRouter { NSURL *url = [NSURL URLWithString:@"WS://www.ws.com/second"]; [WSRouter registerRouterWithPrefixURL:url handler:^UIViewController *(NSURL *URL, UIViewController *sourceViewController) { UIViewController *destViewController = [[WSPresentedViewController alloc] init]; [WSRouter transferViewController:destViewController fromViewController:sourceViewController transition:WSTransitionPresent]; return destViewController; }]; }
|
同一个block跳转不同的页面
值得注意的是,并不是注册一个block只能跳转同一个viewController。我们也可以根据实际情况(比如url中的query参数不同)选择跳转不同的页面,WSRouter也是支持的。但是笔者并不支持这样做。如果我们的工程中存在一个block中根据if…else…语句跳转了不同的页面,那么我们可以考虑对这些不同的页面分开注册。如下:
block中根据query中的web字段是否为ture来区分是否要跳转webViewController。这是一种解决方案,但更好的解决方案是对这两个控制器分开注册。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| + (void)registerRouter {
NSURL *url = [NSURL URLWithString:@"ws://www.ws.com/third"]; [WSRouter registerRouterWithPrefixURL:url handler:^UIViewController *(NSURL *URL, UIViewController *sourceViewController) { UIViewController *destViewController = nil;
NSDictionary *params = [NSString ws_parameterFromURLQuery:URL.query]; if ([params[@"web"] boolValue]) { destViewController = [[WSWebViewController alloc] init]; } else { destViewController = [[WSPushedViewController alloc] init]; }
[WSRouter transferViewController:destViewController fromViewController:sourceViewController transition:WSTransitionPush]; return destViewController; }]; }
|
注意
:注册的URL必须是有效的,需要包括scheme、host、path。如果目的控制器需要业务参数,我们还要在跳转URL中携带query部分。