路由,各个模块之间的调度,跳转。
iOS路由,其实就是一单例类,使用需通过注册组件,调用方通过URL调用服务方页面。通过路由表的映射关系进行关联,调用方可以传入复 杂的参数、对象等。
基本跳转主要是注册组件,调用openURl方法,传入参数即可实现。
反向传值亦可通过参数传递。
JLRoutes路由,控制系统中所有的跳转,目前系统最基本的跳转有三种:
1,Tabbar – Selected;
2,UINavigationController – Push&Pop;
3,UIViewController(UINavigationController)- modal – Present&Dismiss。
JLRoutes是一第三方库,主要保存了当前注册的页面信息,例如class,params,等。
首先它会将所有的类信息封装成一个字典,然后保存在字典里边,键值分别为类信息和类class字符串,注册到路由中之后,等到发送消息时,会返回类的消息,然后可进行操纵。
当当前vc信息注册成功后,再次给vc发送消息时,连通vc的所有保存信息进行返回,然后获取到信息之后再进行操作,其实就是对跳转的一种数据保存然后进行的封装。
最大的好处就是保存字符串,使其内存不会暴增,在运行速率上跟常规没什么两样。
对传参也进行了简洁封装。
回调进行了简洁封装,能保证日常使用,如果有定制化需求,只需要往路由中注册不同的规则即可。
封装后使用:
//头文件
#import "SkyRouter+Handle.h"
//push
[SkyRouter openURL:SkyRouterSecondCtrl parameters:@{SkyRouteSegueType: SkyRouteSeguePush,@"delegate":self}];
//模态并且传递了block
void(^complate)(void) = ^{
NSLog(@"complate");
};
[SkyRouter openURL:SkyRouterSecondCtrl parameters:@{SkyRouteSegueType: SkyRouteSegueModal, SkyRouteSegueNeedNavigation: @(YES),SkyRouteModalCompletionHandleKey:complate,@"delegate":self}];
//
//pop
__weak typeof(self) weakSelf = self;
void(^popEndHandle)(void) = ^(){
if(weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(delegateEvent:)]){
[weakSelf.delegate delegateEvent:@"这是代理内容"];
}
};
//pop
[SkyRouter openURL:SkyRouteSegueBack parameters:@{SkyRouteSegueBackType:SkyRouteSegueBackPop,SkyRoutePopCompletionBlock:popEndHandle}];
//等价于
//[SkyRouter openURL:SkyRouteSegueBack parameters:@{SkyRoutePopCompletionBlock:popEndHandle}];
//
//dismiss
void(^dismissHandle)(void) = ^(){
NSLog(@"%@",@"ssssssssssssssssss");
if(self.delegate && [self.delegate respondsToSelector:@selector(delegateEvent:)]){
[self.delegate delegateEvent:@"这是代理内容"];
}
};
[SkyRouter openURL:SkyRouteSegueBack parameters:@{SkyRouteSegueBackType:SkyRouteSegueBackDismiss,SkyRouteDismissCompletionHandleKey:dismissHandle,@"delegate":self}];
具体代码如下:
//
// SkyRouter+Handle.m
// RouterDemo
//
// Created by skyzizhu on 2020/12/12.
//
#import "SkyRouter+Handle.h"
#import "UIViewController+Index.h"
#import "UIViewController+PopHandle.h"
@implementation SkyRouter (Handle)
+ (void)load {
//系统链接的时候,注册到里边
static dispatch_once_t onceQueue;
dispatch_once(&onceQueue, ^{
[self performSelectorOnMainThread:@selector(sky_registerRouter) withObject:nil waitUntilDone:false];
});
}
+ (void)sky_registerRouter {
//获取全局 RouterMapInfo
NSDictionary* routerMapInfo = [SkyRouterMap skyRouterMapInfo];
// router 对应控制器路径, 使用其来注册 Route, 当调用当前 Route 时会执行回调; 回调参数 parameters: 在执行 Route 时传入的参数;
for (NSString* router in routerMapInfo.allKeys) {
NSDictionary* routerMap = routerMapInfo[router];
NSString* className = routerMap[SkyRouteClassName];
if (IsStringClass(className)) {
/*注册所有控制器 Router, 使用 [... openURL:...]; push 到 AppearVC;
[... openURL: parameters:@{kJSDVCRouteSegue: RouteSegueModal, @"name": @"jersey"}]; Modal 到 Appear VC 并携带参数 name;
*/
[self addRoute:router handler:^BOOL(NSDictionary * _Nonnull parameters) {
//执行路由匹配成功之后,跳转逻辑回调;
// NSMutableDictionary* mapInfo = [NSMutableDictionary dictionaryWithDictionary:parameters];
//
// [mapInfo setValue:className forKey:kJSDVCRouteClassName];
// [mapInfo setValue:routerMap[kJSDVCRouteClassTitle] forKey:kJSDVCRouteClassTitle];
// [mapInfo setValue:routerMap[kJSDVCRouteClassFlags] forKey:kJSDVCRouteClassFlags];
// [mapInfo setValue:@(needLogin) forKey:kJSDVCRouteNeedLogin];
/*执行 Route 回调; 处理控制器跳转 + 传参;
** routerMap: 当前 route 映射的 routeMap; 我们在 RouterConfig 配置的 Map;
** parameters: 调用 route 时, 传入的参数;
*/
return [self executeRouterClassName:className routerMap:routerMap parameters:parameters];
}];
}
}
// 注册 Router 到指定TabBar Index; 使用 [ openURL:SkyRouteMineTab] 切换到 mine Index
[self addRoute:@"/rootTab/:index" handler:^BOOL(NSDictionary * _Nonnull parameters) {
NSInteger index = [parameters[@"index"] integerValue];
// 处理 UITabBarControllerIndex 切换;
UITabBarController* tabBarVC = (UITabBarController* )[UIViewController index_rootViewController];
if ([tabBarVC isKindOfClass:[UITabBarController class]] && index >= 0 && tabBarVC.viewControllers.count >= index) {
UIViewController* indexVC = tabBarVC.viewControllers[index];
if ([indexVC isKindOfClass:[UINavigationController class]]) {
indexVC = ((UINavigationController *)indexVC).topViewController;
}
//传参
[self setupParameters:parameters forViewController:indexVC];
tabBarVC.selectedIndex = index;
return YES;
} else {
return NO;
}
}];
// 注册返回上层页面 Router, 使用 [... parameters:@{kJSDVCRouteBackIndex: @(2)}]返回前两页
[self addRoute:SkyRouteSegueBack handler:^BOOL(NSDictionary * _Nonnull parameters) {
return [self executeBackRouterParameters:parameters];
}];
}
#pragma mark - execute Router VC
// 当查找到指定 Router 时, 触发路由回调逻辑; 找不到已注册 Router 则直接返回 NO; 如需要的话, 也可以在这里注册一个全局未匹配到 Router 执行的回调进行异常处理;
+ (BOOL)executeRouterClassName:(NSString *)className routerMap:(NSDictionary* )routerMap parameters:(NSDictionary* )parameters {
BOOL userIsLogin = NO;//获取当前是否登录
// 拦截 Router 映射参数,是否需要登录才可跳转;
BOOL needLogin = [routerMap[SkyRouteClassNeedLogin] boolValue];
if (needLogin && !userIsLogin) {
//这里打开注册的login页面
[SkyRouter openURL:@""];
return NO;
}
//统一初始化控制器,传参和跳转;
UIViewController* vc = [self viewControllerWithClassName:className routerMap:routerMap parameters: parameters];
if (vc) {
[self gotoViewController:vc parameters:parameters];
return YES;
} else {
return NO;
}
}
// 根据 Router 映射到的类名实例化控制器;
+ (UIViewController *)viewControllerWithClassName:(NSString *)className routerMap:(NSDictionary *)routerMap parameters:(NSDictionary* )parameters {
id vc = [[NSClassFromString(className) alloc] init];
if (![vc isKindOfClass:[UIViewController class]]) {
vc = nil;
}
#if DEBUG
//vc不是UIViewController
NSAssert(vc, @"%s: %@ is not kind of UIViewController class, routerMap: %@",__func__ ,className, routerMap);
#endif
//参数赋值
[self setupParameters:parameters forViewController:vc];
return vc;
}
// 对 VC 参数赋值
+ (void)setupParameters:(NSDictionary *)params forViewController:(UIViewController* )vc {
for (NSString *key in params.allKeys) {
BOOL hasKey = [vc respondsToSelector:NSSelectorFromString(key)];
BOOL notNil = params[key] != nil;
if (hasKey && notNil) {
[vc setValue:params[key] forKey:key];
}
#if DEBUG
//vc没有相应属性,但却传了值
if ([key hasPrefix:@"JLRouteURL"]==NO &&
[key hasPrefix:@"JLRouteURL"]==NO && [params[@"JLRoutePattern"] rangeOfString:[NSString stringWithFormat:@":%@",key]].location==NSNotFound) {
//NSAssert(hasKey == YES, @"%s: %@ is not property for the key %@",__func__ ,vc,key);
}
#endif
};
}
// 跳转和参数设置;
+ (void)gotoViewController:(UIViewController *)vc parameters:(NSDictionary *)parameters {
UIViewController* currentVC = [UIViewController index_findVisibleViewController];
NSString *segue = parameters[SkyRouteSegueType] ? parameters[SkyRouteSegueType] : SkyRouteSeguePush; // 决定 present 或者 Push; 默认值 Push
BOOL animated = parameters[SkyRouteAnimated] ? [parameters[SkyRouteAnimated] boolValue] : YES; // 转场动画;
NSLog(@"%s 跳转: %@ %@ %@",__func__ ,currentVC, segue,vc);
if ([segue isEqualToString:SkyRouteSeguePush]) { //PUSH
if (currentVC.navigationController) {
NSString *backIndexString = [NSString stringWithFormat:@"%@",parameters[SkyRouteBackIndex]];
UINavigationController* nav = currentVC.navigationController;
if ([backIndexString isEqualToString:SkyRouteIndexRoot]) {
NSMutableArray *vcs = [NSMutableArray arrayWithObject:nav.viewControllers.firstObject];
[vcs addObject:vc];
[nav setViewControllers:vcs animated:animated];
} else if ([backIndexString integerValue] && [backIndexString integerValue] < nav.viewControllers.count) {
//移除掉指定数量的 VC, 在Push;
NSMutableArray *vcs = [nav.viewControllers mutableCopy];
[vcs removeObjectsInRange:NSMakeRange(vcs.count - [backIndexString integerValue], [backIndexString integerValue])];
nav.viewControllers = vcs;
[nav pushViewController:vc animated:YES];
} else {
[nav pushViewController:vc animated:animated];
}
}else { //由于无导航栏, 直接执行 Modal
BOOL needNavigation = parameters[SkyRouteSegueNeedNavigation] ? NO : YES;
if (needNavigation) {
UINavigationController* navigationVC = [[UINavigationController alloc] initWithRootViewController:vc];
[currentVC presentViewController:navigationVC animated:YES completion:[parameters objectForKey:SkyRouteModalCompletionHandleKey]];
}
else {
[currentVC presentViewController:vc animated:animated completion:[parameters objectForKey:SkyRouteModalCompletionHandleKey]];
}
}
}
else { //Modal
BOOL needNavigation = parameters[SkyRouteSegueNeedNavigation] ? parameters[SkyRouteSegueNeedNavigation] : NO;
if (needNavigation) {
UINavigationController* navigationVC = [[UINavigationController alloc] initWithRootViewController:vc];
//
[currentVC presentViewController:navigationVC animated:animated completion:[parameters objectForKey:SkyRouteModalCompletionHandleKey]];
}
else {
//vc.modalPresentationStyle = UIModalPresentationFullScreen;
[currentVC presentViewController:vc animated:animated completion:[parameters objectForKey:SkyRouteModalCompletionHandleKey]];
}
}
}
// 返回上层页面回调;
+ (BOOL)executeBackRouterParameters:(NSDictionary *)parameters {
//
UIViewController* visibleVC = [UIViewController index_findVisibleViewController];
//1,首先判断参数是返回dismiss还是pop
//2,如果是pop,则判断有无index,如果有则popto,如果没有则pop
//如果是dismiss,判断是否有navigationVc,如果有,则连通navigationVcdismiss
//如果没有,则直接dismiss VC
//默认是pop
//
//是否执行动画,默认执行
BOOL animated = parameters[SkyRouteAnimated] ? [parameters[SkyRouteAnimated] boolValue] : YES;
//获取返回类型,默认是pop
NSString *backType = parameters[SkyRouteSegueBackType] ? parameters[SkyRouteSegueBackType] : SkyRouteSegueBackPop;
//如果是dismiss,则处理dismiss事件
if([backType isEqualToString:SkyRouteSegueBackDismiss]){
//判断当前dismiss时是否带有NavigationController,默认没有
BOOL hasNaviCtrlByDismiss = parameters[SkyRouteSegueNeedNavigation] ? [parameters[SkyRouteSegueNeedNavigation] boolValue] : NO;
if(hasNaviCtrlByDismiss){
if(!visibleVC.navigationController){
return NO;
}
[visibleVC.navigationController dismissViewControllerAnimated:animated completion:[parameters objectForKey:SkyRouteDismissCompletionHandleKey]];
}else{
[visibleVC dismissViewControllerAnimated:animated completion:[parameters objectForKey:SkyRouteDismissCompletionHandleKey]];
}
return YES;
//[parameters objectForKey:SkyRouteDismissCompletionHandleKey]
//为dismiss后参数传过来的block,要dismiss的controller这么写
/*
void(^dismissHandle)(void) = ^(){
NSLog(@"%@",@"ssssssssssssssssss");
if(self.delegate && [self.delegate respondsToSelector:@selector(delegateEvent:)]){
[self.delegate delegateEvent:@"这是代理内容"];
}
};
[SkyRouter openURL:SkyRouteSegueBack parameters:@{SkyRouteSegueBackType:SkyRouteSegueBackDismiss,SkyRouteDismissCompletionHandleKey:dismissHandle,@"delegate":self}];
*/
}
//这里全部是pop的事件
NSString *backIndexString = parameters[SkyRouteBackIndex] ? [NSString stringWithFormat:@"%@",parameters[SkyRouteBackIndex]] : nil; // 指定返回个数, 优先处理此参数;
id backPage = parameters[SkyRouteBackPage] ? parameters[SkyRouteBackPage] : nil; // 指定返回到某个页面,
NSInteger backPageOffset = parameters[SkyRouteBackPageOffset] ? [parameters[SkyRouteBackPageOffset] integerValue] : 0; // 指定返回到的页面并进行偏移;
// UIViewController* visibleVC = [UIViewController index_findVisibleViewController];
UINavigationController* navigationVC = visibleVC.navigationController;
if (navigationVC) {
// 处理 pop 按索引值处理;
if (IsStringClass(backIndexString)) {
if ([backIndexString isEqualToString:SkyRouteIndexRoot]) {//返回根
[navigationVC popToRootViewControllerAnimated:animated];
}else {
NSUInteger backIndex = backIndexString.integerValue;
NSMutableArray* vcs = navigationVC.viewControllers.mutableCopy;
if (vcs.count > backIndex) {
[vcs removeObjectsInRange:NSMakeRange(vcs.count - backIndex, backIndex)];
[navigationVC setViewControllers:vcs animated:animated];
return YES;
}else {
return NO; //指定返回索引值超过当前导航控制器包含的子控制器;
}
}
}
else if (backPage) { //处理返回指定的控制器, 可以处理
NSMutableArray *vcs = navigationVC.viewControllers.mutableCopy;
NSInteger pageIndex = NSNotFound;
//页面标识为字符串
if ([backPage isKindOfClass:[NSString class]]) {
for (int i=0; i<vcs.count; i++) {
if ([vcs[i] isKindOfClass:NSClassFromString(backPage)]) {
pageIndex = i;
break;
}
}
}
//页面标识为vc实例
else if ([backPage isKindOfClass:[UIViewController class]]) {
for (int i=0; i<vcs.count; i++) {
if (vcs[i] == backPage) {
pageIndex = i;
break;
}
}
}
//有指定页面,根据参数跳转
if (pageIndex != NSNotFound) {
NSUInteger backIndex = (vcs.count-1) - pageIndex + backPageOffset;
if (vcs.count > backIndex) {
[vcs removeObjectsInRange:NSMakeRange(vcs.count-backIndex, backIndex)];
[navigationVC setViewControllers:vcs animated:animated];
return YES;
}
}
//指定页面不存在,return NO,可用于判断当前vc栈里有没有当前页面。
}
else {
//
[navigationVC popViewControllerAnimated:animated];
void(^popEndBlock)(void) = [parameters objectForKey:SkyRoutePopCompletionBlock];
if(popEndBlock){
//pop传递代理执行的block
[visibleVC setNavigationControllerDelegate:visibleVC popHandle:popEndBlock];
//将要pop的controller的写法
/* 传递一个block到参数,然后让其navigationController代理去执行
__weak typeof(self) weakSelf = self;
void(^popEndHandle)(void) = ^(){
if(weakSelf.delegate && [weakSelf.delegate respondsToSelector:@selector(delegateEvent:)]){
[weakSelf.delegate delegateEvent:@"这是代理内容"];
}
};
[SkyRouter openURL:SkyRouteSegueBack parameters:@{SkyRouteSegueBackType:SkyRouteSegueBackPop,SkyRoutePopCompletionBlock:popEndHandle}];
*/
}
return YES;
}
}
return NO;
}
@end
Demo:
http://image.iashes.com/content-blog/file/RouterDemo.zip

