Objective-C 路由表原理详解
在 Objective-C 中实现路由表是组件化架构的核心,它通过 URL 映射机制实现模块间解耦通信。以下是完整实现原理:
一、核心架构设计
二、路由表实现原理
1. 路由条目类设计
// RouteEntry.h
@interface RouteEntry : NSObject
@property (nonatomic, copy) NSString *pattern; // 路由模式
@property (nonatomic, copy) id (^handler)(NSDictionary *params); // 处理闭包
@property (nonatomic, strong) NSArray<NSString *> *keys; // 参数键名
@property (nonatomic, assign) NSInteger priority; // 匹配优先级
@end// RouteEntry.m
@implementation RouteEntry
@end
2. 路由表核心类
// Router.h
@interface Router : NSObject+ (instancetype)sharedRouter;- (void)registerPattern:(NSString *)pattern handler:(id (^)(NSDictionary *params))handler;- (void)registerPattern:(NSString *)pattern handler:(id (^)(NSDictionary *params))handler priority:(NSInteger)priority;- (id)openURL:(NSString *)url;
- (id)openURL:(NSString *)url withParams:(NSDictionary *)additionalParams;@end
3. 路由注册实现
// Router.m
@implementation Router {NSMutableDictionary<NSString *, RouteEntry *> *_staticRoutes;NSMutableArray<RouteEntry *> *_dynamicRoutes; // 存储动态路由
}+ (instancetype)sharedRouter {static Router *instance = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{instance = [[Router alloc] init];});return instance;
}- (instancetype)init {self = [super init];if (self) {_staticRoutes = [NSMutableDictionary dictionary];_dynamicRoutes = [NSMutableArray array];}return self;
}- (void)registerPattern:(NSString *)pattern handler:(id (^)(NSDictionary *params))handler priority:(NSInteger)priority {// 解析模式中的参数NSMutableArray *keys = [NSMutableArray array];NSString *transformedPattern = [self transformPattern:pattern keys:keys];RouteEntry *entry = [[RouteEntry alloc] init];entry.pattern = pattern;entry.handler = handler;entry.keys = [keys copy];entry.priority = priority;// 静态路由(无参数)if (keys.count == 0) {_staticRoutes[pattern] = entry;} // 动态路由(含参数)else {[_dynamicRoutes addObject:entry];// 按优先级排序[_dynamicRoutes sortUsingComparator:^NSComparisonResult(RouteEntry *e1, RouteEntry *e2) {return [@(e2.priority) compare:@(e1.priority)];}];}}
4. URL 匹配算法
- (id)openURL:(NSString *)url withParams:(NSDictionary *)additionalParams {// 1. 尝试精确匹配静态路由RouteEntry *staticEntry = _staticRoutes[url];if (staticEntry) {return staticEntry.handler(additionalParams ?: @{});}// 2. 动态路由匹配NSURLComponents *components = [NSURLComponents componentsWithString:url];NSString *path = components.path;for (RouteEntry *entry in _dynamicRoutes) {// 将模式转换为正则表达式NSString *regexPattern = [self regexPatternForRoute:entry.pattern];NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexPattern options:0 error:nil];NSArray *matches = [regex matchesInString:path options:0 range:NSMakeRange(0, path.length)];if (matches.count > 0) {NSTextCheckingResult *match = matches[0];NSMutableDictionary *params = [NSMutableDictionary dictionary];// 提取路径参数for (int i = 0; i < entry.keys.count; i++) {NSString *key = entry.keys[i];NSRange range = [match rangeAtIndex:i+1];if (range.location != NSNotFound) {NSString *value = [path substringWithRange:range];params[key] = value;}}// 添加查询参数for (NSURLQueryItem *item in components.queryItems) {params[item.name] = item.value;}// 合并额外参数if (additionalParams) {[params addEntriesFromDictionary:additionalParams];}return entry.handler(params);}}// 3. 未找到匹配路由[self handleUnmatchedURL:url];return nil;
}
5. 模式转换方法
- (NSString *)regexPatternForRoute:(NSString *)routePattern {// 转换模式如 /user/:id 为正则表达式NSString *pattern = [routePattern stringByReplacingOccurrencesOfString:@":" withString:@""];// 处理通配符pattern = [pattern stringByReplacingOccurrencesOfString:@"*" withString:@".*"];// 添加正则捕获组NSRegularExpression *paramRegex = [NSRegularExpression regularExpressionWithPattern:@":(\\w+)" options:0 error:nil];__block NSString *result = routePattern;__block NSInteger offset = 0;[paramRegex enumerateMatchesInString:routePattern options:0 range:NSMakeRange(0, routePattern.length) usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop) {NSRange fullRange = [match rangeAtIndex:0];NSRange keyRange = [match rangeAtIndex:1];// 调整位置偏移量fullRange.location += offset;keyRange.location += offset;NSString *replacement = [NSString stringWithFormat:@"([^/]+)"];result = [result stringByReplacingCharactersInRange:fullRange withString:replacement];offset += replacement.length - fullRange.length;}];// 添加边界匹配return [NSString stringWithFormat:@"^%@$", result];
}
三、路由匹配优先级系统
四、企业级优化策略
1. 路由缓存机制
// 在Router类中添加
@property (nonatomic, strong) NSCache *routeCache;- (id)cachedRouteForURL:(NSString *)url {if (!_routeCache) {_routeCache = [[NSCache alloc] init];_routeCache.countLimit = 100; // 限制缓存条目数}return [_routeCache objectForKey:url];
}- (void)cacheRouteResult:(id)result forURL:(NSString *)url {if (result && url) {[_routeCache setObject:result forKey:url];}
}// 在openURL方法中使用
- (id)openURL:(NSString *)url withParams:(NSDictionary *)additionalParams {// 先检查缓存id cachedResult = [self cachedRouteForURL:url];if (cachedResult) {return cachedResult;}// ...匹配逻辑// 缓存结果if (result) {[self cacheRouteResult:result forURL:url];}return result;
}
2. 路由守卫系统
// Router.h
typedef BOOL (^RouteGuardHandler)(NSString *url, NSDictionary **params);- (void)addGlobalGuard:(RouteGuardHandler)guard;
// Router.m
@implementation Router {NSMutableArray<RouteGuardHandler> *_globalGuards;
}- (void)addGlobalGuard:(RouteGuardHandler)guard {if (guard) {[_globalGuards addObject:guard];}
}- (BOOL)executeGuardsForURL:(NSString *)url params:(NSDictionary **)params {for (RouteGuardHandler guard in _globalGuards) {NSDictionary *tempParams = *params;if (!guard(url, &tempParams)) {return NO;}*params = tempParams;}return YES;
}// 在openURL方法中调用
- (id)openURL:(NSString *)url withParams:(NSDictionary *)additionalParams {// ...匹配逻辑// 执行路由守卫if (![self executeGuardsForURL:url params:&finalParams]) {return nil; // 守卫拦截}// ...继续执行
}
3. 路由表调试工具
- (void)printAllRoutes {NSLog(@"===== Static Routes =====");[_staticRoutes enumerateKeysAndObjectsUsingBlock:^(NSString *key, RouteEntry *entry, BOOL *stop) {NSLog(@"%@ -> %@", key, entry.pattern);}];NSLog(@"===== Dynamic Routes =====");for (RouteEntry *entry in _dynamicRoutes) {NSLog(@"%@ (priority: %ld)", entry.pattern, (long)entry.priority);}
}- (BOOL)isRouteRegistered:(NSString *)pattern {if (_staticRoutes[pattern]) {return YES;}for (RouteEntry *entry in _dynamicRoutes) {if ([entry.pattern isEqualToString:pattern]) {return YES;}}return NO;
}
五、使用示例
1. 注册路由
// App启动时注册路由
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {Router *router = [Router sharedRouter];// 注册用户详情页[router registerPattern:@"/user/profile/:userId" handler:^id(NSDictionary *params) {NSString *userId = params[@"userId"];UserProfileVC *vc = [[UserProfileVC alloc] initWithUserId:userId];[self.navigationController pushViewController:vc animated:YES];return vc;} priority:10];// 注册设置页[router registerPattern:@"/settings" handler:^id(NSDictionary *params) {SettingsVC *vc = [[SettingsVC alloc] init];[self presentViewController:vc animated:YES completion:nil];return vc;} priority:5];return YES;
}
2. 使用路由跳转
// 在需要跳转的地方
- (void)showUserProfile:(NSString *)userId {Router *router = [Router sharedRouter];NSString *url = [NSString stringWithFormat:@"myapp://user/profile/%@", userId];// 带额外参数NSDictionary *params = @{@"source": @"home_page"};[router openURL:url withParams:params];
}
3. 处理深度链接
// 处理AppDelegate中的深度链接
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {Router *router = [Router sharedRouter];return [router openURL:url.absoluteString] != nil;}
六、性能优化策略
优化技术 | 实现方式 | 性能提升 |
---|---|---|
正则预编译 | 注册时编译正则表达式 | 减少70%匹配时间 |
路由缓存 | 使用NSCache缓存结果 | 减少60%匹配计算 |
优先级排序 | 高优先级路由前置 | 平均减少50%匹配尝试 |
守卫短路 | 守卫失败时提前终止 | 减少不必要的处理 |
七、特殊场景处理
1. 通配符路由
// 注册通配符路由
[router registerPattern:@"/files/*" handler:^id(NSDictionary *params) {NSString *filePath = params[@"wildcard"];FileViewer *viewer = [[FileViewer alloc] initWithFilePath:filePath];return viewer;
} priority:1];
2. 多参数路由
// 注册多参数路由
[router registerPattern:@"/search/:category/:keyword" handler:^id(NSDictionary *params) {NSString *category = params[@"category"];NSString *keyword = params[@"keyword"];SearchResultsVC *vc = [[SearchResultsVC alloc] initWithCategory:category keyword:keyword];return vc;
} priority:8];
3. 路由重定向
// 实现重定向
[router registerPattern:@"/old/path" handler:^id(NSDictionary *params) {// 重定向到新路径[[Router sharedRouter] openURL:@"/new/path"];return nil;
} priority:3];
八、路由表 vs 其他通信方式
特性 | 路由表 | 通知中心 | 委托模式 |
---|---|---|---|
解耦程度 | ★★★★★ | ★★★☆☆ | ★★☆☆☆ |
类型安全 | ★★☆☆☆ | ★☆☆☆☆ | ★★★★★ |
跨组件通信 | ★★★★★ | ★★★★★ | ★★☆☆☆ |
可维护性 | ★★★☆☆ | ★★☆☆☆ | ★★★★☆ |
深度链接支持 | ★★★★★ | ☆☆☆☆☆ | ☆☆☆☆☆ |
九、最佳实践建议
路由命名规范
// 使用反向DNS风格
@"com.yourapp.module.action"
// 或RESTful风格
@"/user/{id}/profile"
路由版本管理
// v1路由
[router registerPattern:@"/v1/user/profile" ...];// v2路由
[router registerPattern:@"/v2/user/profile" ...];
路由文档自动化
// 使用注释生成文档
/// ROUTE: /user/profile
/// DESC: 显示用户详情页
/// PARAMS: userId - 用户ID
路由监控系统
// 统计路由使用情况
- (id)openURL:(NSString *)url withParams:(NSDictionary *)additionalParams {[Analytics trackEvent:@"route_open" properties:@{@"url": url}];// ...原有逻辑
}
路由表是 Objective-C 组件化架构的核心基础设施,合理设计路由系统可以大幅提升代码的可维护性和扩展性,同时为深度链接、动态化等高级功能提供基础支持。