前言
在APP开发过程中,必然会遇到在WebView和推送消息中打开其他页面的需求,进一步则是在任何动态界面.
但随着APP越来越大,功能模块越来越复杂,采用传统的控制器跳转方式,需要持有跳转对象,就会造成复杂的依赖链,代码耦合性变强.
采用Routable的方式进行动态界面跳转则不会有这个问题.
传统跳转:
ProjectDetailViewController* pro = [[ProjectDetailViewController alloc]init];
pro.StrID = @"XX";
pro.Memo = @"XX";
[self.navigationController pushViewController:pro animated:YES];
Routable跳转:
[[Routable sharedRouter] open:@"ProjectDetail/XX/XX"];
Routable使用
1.注册协议
//一般在APP入口didFinishLaunchingWithOptions中进行注册
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
//map规则 @"跳转标识/:参数1/:参数2...."
[[Routable sharedRouter] setNavigationController:nav];
[[Routable sharedRouter] map:@"ProjectDetail/:StrID/:Memo/:Name" toController:[ProjectDetailViewController class]];
}
2.使用协议进行跳转
//open规则 @"跳转标识/参数1/参数2"
[[Routable sharedRouter] open:@"ProjectDetail/XX/XX"];
Routable代码解析
关键方法:sharedRouter
map
open
setNavigationController
sharedRouter方法:
//使用dispatch_once初始化单例对象 保证一个程序生命周期中使用同一个Router对象
+ (instancetype)sharedRouter {
static Routable *_sharedRouter = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_sharedRouter = [[Routable alloc] init];
});
return _sharedRouter;
}
map方法:
- (void)map:(NSString *)format toController:(Class)controllerClass withOptions:(UPRouterOptions *)options {
if (!format) {
@throw [NSException exceptionWithName:@"RouteNotProvided"
reason:@"Route #format is not initialized"
userInfo:nil];
return;
}
if (!options) {
options = [UPRouterOptions routerOptions];
}
options.openClass = controllerClass;
//关键代码 创建UPRouterOptions对象 将传入的类对象作为value 参数字符串作为key存储在可变字典
[self.routes setObject:options forKey:format];
}
setNavigationController方法:
//Router对象中有一个navigationController参数 用来保存传入的导航视图控制器 在open方法中会使用这个导航视图控制器进行跳转
@property (readwrite, nonatomic, strong) UINavigationController *navigationController;
open方法:
//调用Router类中的该方法 将传入的参数格式化成RouterParams对象
//再通过RouterParams对象从self.routes中获取对应的openClass类对象
//使用navigationController进行跳转
- (void)open:(NSString *)url
animated:(BOOL)animated
extraParams:(NSDictionary *)extraParams
{
RouterParams *params = [self routerParamsForUrl:url extraParams: extraParams];
UPRouterOptions *options = params.routerOptions;
if (options.callback) {
RouterOpenCallback callback = options.callback;
callback([params controllerParams]);
return;
}
if (!self.navigationController) {
if (_ignoresExceptions) {
return;
}
@throw [NSException exceptionWithName:@"NavigationControllerNotProvided"
reason:@"Router#navigationController has not been set to a UINavigationController instance"
userInfo:nil];
}
UIViewController *controller = [self controllerForRouterParams:params];
if (self.navigationController.presentedViewController) {
[self.navigationController dismissViewControllerAnimated:animated completion:nil];
}
if ([options isModal]) {
if ([controller.class isSubclassOfClass:UINavigationController.class]) {
[self.navigationController presentViewController:controller
animated:animated
completion:nil];
}
else {
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:controller];
navigationController.modalPresentationStyle = controller.modalPresentationStyle;
navigationController.modalTransitionStyle = controller.modalTransitionStyle;
[self.navigationController presentViewController:navigationController
animated:animated
completion:nil];
}
}
else if (options.shouldOpenAsRootViewController) {
[self.navigationController setViewControllers:@[controller] animated:animated];
}
else {
[self.navigationController pushViewController:controller animated:animated];
}
}