一步步構(gòu)建iOS路由
接上一篇移動端路由層設(shè)計
為啥要說iOS路由呢?
路由層其實在邏輯上的設(shè)計都是一樣的,關(guān)于對界面跳轉(zhuǎn)的實現(xiàn)部分卻與Android平臺和iOS平臺上的導(dǎo)航機制有著非常緊密的關(guān)系,Android操作系統(tǒng)有著天然的架構(gòu)優(yōu)勢,Intent機制可以協(xié)助應(yīng)用間的交互與通訊,是對調(diào)用組件和數(shù)據(jù)傳遞的描述,本身這種機制就解除了代碼邏輯和界面之間的依賴關(guān)系,只有數(shù)據(jù)依賴。而iOS的界面導(dǎo)航和轉(zhuǎn)場機制則大部分依賴UI組件各自的實現(xiàn),所以如何解決這個問題,iOS端路由的實現(xiàn)則比較有代表性。
其實說白一點,路由層解決的核心問題就是原來界面或者組件之間相互調(diào)用都必須相互依賴,需要導(dǎo)入目標(biāo)的頭文件、需要清楚目標(biāo)對象的邏輯,而現(xiàn)在全部都通過路由中轉(zhuǎn),只依賴路由,或者依靠一些消息傳遞機制連路由都不依賴。其次,路由的核心邏輯就是目標(biāo)匹配,對于外部調(diào)用的情況來說,URL如何匹配Handler是最為重要的,匹配就必然用到正則表達(dá)式。了解這些關(guān)鍵點以后就有了設(shè)計的目的性,let‘s do it~
設(shè)計類圖:
RouteClassMap.png
這里面有如下幾個類:
- WLRRouteRequest,路由層的請求,無論是跨應(yīng)用的外部調(diào)用還是內(nèi)部調(diào)用,最后都形成一個路由請求,該請求包含了URL上的queryparameters和路徑參數(shù),還有內(nèi)部調(diào)用時直接傳入的原生參數(shù),還有請求發(fā)起者對目標(biāo)預(yù)留的回調(diào)block
- WLRRouteHandler,路由層的handler處理,handler接收一個WLRRouteRequest對象,來完成是否是界面跳轉(zhuǎn),還是組件加載,還是內(nèi)部邏輯
- WLRRouter,路由核心對象,內(nèi)部持有注冊的Handler,比方說負(fù)責(zé)界面跳轉(zhuǎn)的Handler,負(fù)責(zé)組件加載的Handler,負(fù)責(zé)API的Handler等等,路由的作用就是將外部調(diào)用傳入的URL或者是內(nèi)部調(diào)用傳入的target,在內(nèi)部匹配上對應(yīng)的handler,然后調(diào)用生命周期方法,完成處理過程,當(dāng)然,圖中還有route的中間件,實際上是預(yù)留AOP的口子,方面后期擴展
- WLRRouteMatcher,用以處理外部調(diào)用的URL是否能與預(yù)設(shè)的正則表達(dá)式匹配,在WLRRouter中,每一次注冊一個handler,都會用一個URL匹配的表達(dá)式生成一個WLRRouteMatcher
- WLRRegularExpression,繼承NSRegularExpression,用以匹配URL,WLRRouteMatcher內(nèi)部有一個WLRRegularExpression對象,WLRRouteMatcher接受一個URL,會使用WLRRegularExpression生成一個WLRMatchResult對象,來確定是否匹配成功,如果匹配成果則將URL上的路徑參數(shù)給取出來
- WLRMatchResult,用以描述WLRRegularExpression的匹配結(jié)果,包含路徑參數(shù)
工作流程:
- App啟動實例化WLRRouter對象
- 實例化WLRRouteHandler對象
- WLRRouter對象掛載WLRRouteHandler實例與URL的表達(dá)式相對應(yīng),WLRRouter內(nèi)部生成一個WLRRouteMatcher對象,與URL的表達(dá)式相對應(yīng)
- 外部調(diào)用的URL和callback傳入WLRRouter對象
- WLRRouter對象遍歷內(nèi)部持有的URL的匹配表達(dá)式,并找到每一個WLRRouteMatcher對象,將URL傳入看是否能返回WLRRouteRequest對象
- 將WLRRouteRequest對象傳入對應(yīng)的WLRRouteHandler對象
- WLRRouteHandler對象根據(jù)WLRRouteRequest尋找到TargetViewController和SourceViewController,在生命周期函數(shù)里,完成參數(shù)傳遞與視圖轉(zhuǎn)場
WLRRouteRequest:
了解了以上,我們從WLRRouteRequest入手。
其實WLRRouteRequest跟NSURLRequest差不多,不過WLRRouteRequest繼承NSObject,實現(xiàn)NSCopying協(xié)議,大概如下:
- #import
- @interface WLRRouteRequest : NSObject
- //外部調(diào)用的URL
- @property (nonatomic, copy, readonly) NSURL *URL;
- //URL表達(dá)式,比方說調(diào)用登錄界面的表達(dá)式可以為:AppScheme://user/login/138********,那URL的匹配表達(dá)式可以是:/login/:phone([0-9]+),路徑必須以/login開頭,后面接0-9的電話號碼數(shù)字,當(dāng)然你也可以直接把電話號碼的正則匹配寫全
- @property(nonatomic,copy)NSString * routeExpression;
- //如果URL是AppScheme://user/login/138********?/callBack="",那么這個callBack就出現(xiàn)在這
- @property (nonatomic, copy, readonly) NSDictionary *queryParameters;
- //這里面會出現(xiàn){@"phone":@"138********"}
- @property (nonatomic, copy, readonly) NSDictionary *routeParameters;
- //這里面存放的是內(nèi)部調(diào)用傳遞的原生參數(shù)
- @property (nonatomic, copy, readonly) NSDictionary *primitiveParams;
- //自動檢測竊取回調(diào)的callBack 的Url
- @property (nonatomic, strong) NSURL *callbackURL;
- //目標(biāo)的viewcontrolller或者是組件可以通過這個
- @property(nonatomic,copy)void(^targetCallBack)(NSError *error,id responseObject);
- //用以表明該request是否被消費
- @property(nonatomic)BOOL isConsumed;
- //簡便方法,用以下標(biāo)法取參數(shù)
- - (id)objectForKeyedSubscript:(NSString *)key;
- //初始化方法
- -(instancetype)initWithURL:(NSURL *)URL routeExpression:(NSString *)routeExpression routeParameters:(NSDictionary *)routeParameters primitiveParameters:(NSDictionary *)primitiveParameters targetCallBack:(void(^)(NSError * error,id responseObject))targetCallBack;
- -(instancetype)initWithURL:(NSURL *)URL;
- //默認(rèn)完成目標(biāo)的回調(diào)
- -(void)defaultFinishTargetCallBack;
- @end
NSURLRequest其實應(yīng)該是個值類型的對象,所以實現(xiàn)拷貝協(xié)議,該對象的實現(xiàn)部分沒有什么可講的,對照源代碼查閱即可。
WLRRouteHandler
- #import
- @class WLRRouteRequest;
- @interface WLRRouteHandler : NSObject
- //即將handle某一個請求
- - (BOOL)shouldHandleWithRequest:(WLRRouteRequest *)request;
- //根據(jù)request取出調(diào)用的目標(biāo)視圖控制器
- -(UIViewController *)targetViewControllerWithRequest:(WLRRouteRequest *)request;
- //根據(jù)request取出來源的視圖控制器
- -(UIViewController *)sourceViewControllerForTransitionWithRequest:(WLRRouteRequest *)request;
- //開始進(jìn)行轉(zhuǎn)場
- -(BOOL)transitionWithRequest:(WLRRouteRequest *)request error:(NSError *__autoreleasing *)error;
- @end
當(dāng)WLRRouter對象完成了URL的匹配生成Request,并尋找到Handler的時候,首先會調(diào)用- (BOOL)shouldHandleWithRequest:(WLRRouteRequest *)request;,來確定handler是否愿意處理,如果愿意,則調(diào)用-(BOOL)transitionWithRequest:(WLRRouteRequest *)request error:(NSError *__autoreleasing *)error;,內(nèi)部則通過便利方法獲取targetViewController與SourceViewController,然后進(jìn)行轉(zhuǎn)場,核心方法的實現(xiàn)為:
- -(BOOL)transitionWithRequest:(WLRRouteRequest *)request error:(NSError *__autoreleasing *)error{
- UIViewController * sourceViewController = [self sourceViewControllerForTransitionWithRequest:request];
- UIViewController * targetViewController = [self targetViewControllerWithRequest:request];
- if ((![sourceViewController isKindOfClass:[UIViewController class]])||(![targetViewController isKindOfClass:[UIViewController class]])) {
- *error = [NSError WLRTransitionError];
- return NO;
- }
- if (targetViewController != nil) {
- targetViewController.wlr_request = request;
- }
- if ([self preferModalPresentationWithRequest:request]||![sourceViewController isKindOfClass:[UINavigationController class]]) {
- [sourceViewController presentViewController:targetViewController animated:YES completion:nil];
- }
- else if ([sourceViewController isKindOfClass:[UINavigationController class]]){
- UINavigationController * nav = (UINavigationController *)sourceViewController;
- [nav pushViewController:targetViewController animated:YES];
- }
- return YES;
- }
- - (BOOL)preferModalPresentationWithRequest:(WLRRouteRequest *)request;{
- return NO;
- }
這里根據(jù)SourceController的類型進(jìn)行判斷,其實request對象的信息足夠可以判斷目標(biāo)視圖應(yīng)該如何打開,從本質(zhì)上來講,URL的匹配表達(dá)式是跟業(yè)務(wù)強關(guān)聯(lián)的也是跟UI交互邏輯強關(guān)聯(lián)的,transitionWithRequest方法實現(xiàn)里,你大可以繼承一下,然后重寫轉(zhuǎn)場過程,甚至你可以在這自己設(shè)置iOS7自定義的轉(zhuǎn)場,提供動畫控制器和實現(xiàn)轉(zhuǎn)場協(xié)議的對象,進(jìn)而可以整體的控制Appp內(nèi)部的實現(xiàn)。
WLRRegularExpression
該類繼承NSRegularExpression
- #import
- @class WLRMatchResult;
- @interface WLRRegularExpression : NSRegularExpression
- //傳入一個URL返回一個匹配結(jié)果
- -(WLRMatchResult *)matchResultForString:(NSString *)string;
- //根據(jù)一個URL的表達(dá)式創(chuàng)建一個WLRRegularExpression實例
- +(WLRRegularExpression *)expressionWithPattern:(NSString *)pattern;
- @end
該對象主要的功能是將一個URL傳入查看是否匹配,并且將表達(dá)式上聲明的路徑參數(shù)從URL上取下來。
比說,我們設(shè)置的URL匹配的表達(dá)式是: login/:phone([0-9]+),那AppScheme://user/login/138** 這樣的URL應(yīng)該是匹配,并且將138的手機號取出來,對應(yīng)到phone上,這個過程必須用到正則表達(dá)式的分組提取子串的功能,:phone是約定好的提取子串的值對應(yīng)的key的名字,其實這個url的正則表達(dá)式應(yīng)該是: /login/([0-9]+)$,那么WLRRegularExpression對象需要知道需要提取所有子串的key還有將URL匹配的表達(dá)式轉(zhuǎn)換為真正的正則表達(dá)式。
- -(instancetype)initWithPattern:(NSString *)pattern options:(NSRegularExpressionOptions)options error:(NSError * _Nullable __autoreleasing *)error{
- //初始化方法中將URL匹配的表達(dá)式pattern轉(zhuǎn)換為真正的正則表達(dá)式
- NSString *transformedPattern = [WLRRegularExpression transfromFromPattern:pattern];
- //用轉(zhuǎn)化后的結(jié)果初始化父類
- if (self = [super initWithPattern:transformedPattern options:options error:error]) {
- //同時將需要提取的子串的值的Key保存到數(shù)組中
- self.routerParamNamesArr = [[self class] routeParamNamesFromPattern:pattern];
- }
- return self;
- }
- //轉(zhuǎn)換為正則表達(dá)式
- +(NSString*)transfromFromPattern:(NSString *)pattern{
- //將pattern拷貝
- NSString * transfromedPattern = [NSString stringWithString:pattern];
- //利用:[a-zA-Z0-9-_][^/]+這個正則表達(dá)式,將URL匹配的表達(dá)式的子串key提取出來,也就是像 /login/:phone([0-9]+)/:name[a-zA-Z-_]這樣的pattern,需要將:phone([0-9]+)和:name[a-zA-Z-_]提取出來
- NSArray * paramPatternStrings = [self paramPatternStringsFromPattern:pattern];
- NSError * err;
- //再根據(jù):[a-zA-Z0-9-_]+這個正則表達(dá)式,將帶有提取子串的key全部去除,比如將:phone([0-9]+)去除:phone改成([0-9]+)
- NSRegularExpression * paramNamePatternEx = [NSRegularExpression regularExpressionWithPattern:WLRRouteParamNamePattern options:NSRegularExpressionCaseInsensitive error:&err];
- for (NSString * paramPatternString in paramPatternStrings) {
- NSString * replaceParamPatternString = [paramPatternString copy];
- NSTextCheckingResult * foundParamNamePatternResult =[paramNamePatternEx matchesInString:paramPatternString options:NSMatchingReportProgress range:NSMakeRange(0, paramPatternString.length)].firstObject;
- if (foundParamNamePatternResult) {
- NSString *paramNamePatternString =[paramPatternString substringWithRange: foundParamNamePatternResult.range];
- replaceParamPatternString = [replaceParamPatternString stringByReplacingOccurrencesOfString:paramNamePatternString withString:@""];
- }
- if (replaceParamPatternString.length == 0) {
- replaceParamPatternString = WLPRouteParamMatchPattern;
- }
- transfromedPattern = [transfromedPattern stringByReplacingOccurrencesOfString:paramPatternString withString:replaceParamPatternString];
- }
- if (transfromedPattern.length && !([transfromedPattern characterAtIndex:0] == '/')) {
- transfromedPattern = [@"^" stringByAppendingString:transfromedPattern];
- }
- //最后結(jié)尾要用$符號
- transfromedPattern = [transfromedPattern stringByAppendingString:@"$"];
- //最后會將/login/:phone([0-9]+)轉(zhuǎn)換為login/([0-9]+)$
- return transfromedPattern;
- }
在Matcher對象匹配一個URL的時候
- -(WLRMatchResult *)matchResultForString:(NSString *)string{
- //首先通過自身方法將URL進(jìn)行匹配得出NSTextCheckingResult結(jié)果的數(shù)組
- NSArray * array = [self matchesInString:string options:0 range:NSMakeRange(0, string.length)];
- WLRMatchResult * result = [[WLRMatchResult alloc]init];
- if (array.count == 0) {
- return result;
- }
- result.match = YES;
- NSMutableDictionary * paramDict = [NSMutableDictionary dictionary];
- //遍歷NSTextCheckingResult結(jié)果
- for (NSTextCheckingResult * paramResult in array) {
- //再便利根據(jù)初始化的時候提取的子串的Key的數(shù)組
- for (int i = 1; i<paramResult.numberOfRanges&&i <= self.routerParamNamesArr.count;i++ ) {
- NSString * paramName = self.routerParamNamesArr[i-1];
- //將值取出,然后將key和value放入到paramDict
- NSString * paramValue = [string substringWithRange:[paramResult rangeAtIndex:i]];
- [paramDict setObject:paramValue forKey:paramName];
- }
- }
- //最后賦值給WLRMatchResult對象
- result.paramProperties = paramDict;
- return result;
- }
核心代碼總共80多行,源碼大家可以詳閱
WLRRouteMatcher
- #import
- @class WLRRouteRequest;
- @interface WLRRouteMatcher : NSObject
- //傳入URL匹配的表達(dá)式,獲取一個matcher實例
- +(instancetype)matcherWithRouteExpression:(NSString *)expression;
- //傳入URL,如果能匹配上,則生成WLRRouteRequest對象,同時將各種參數(shù)解析好交由WLRRouteRequest攜帶
- -(WLRRouteRequest *)createRequestWithURL:(NSURL *)URL primitiveParameters:(NSDictionary *)primitiveParameters targetCallBack:(void(^)(NSError *, id responseObject))targetCallBack;
- @end
屬性有如下:
- //scheme
- @property(nonatomic,copy) NSString * scheme;
- //WLRRegularExpression的實例
- @property(nonatomic,strong)WLRRegularExpression * regexMatcher;
- //匹配的表達(dá)式
- @property(nonatomic,copy)NSString * routeExpressionPattern;
初始化方法:
- -(instancetype)initWithRouteExpression:(NSString *)routeExpression{
- if (![routeExpression length]) {
- return nil;
- }
- if (self = [super init]) {
- //將scheme與path部分分別取出
- NSArray * parts = [routeExpression componentsSeparatedByString:@"://"];
- _scheme = parts.count>1?[parts firstObject]:nil;
- _routeExpressionPattern =[parts lastObject];
- //將path部分當(dāng)做URL匹配表達(dá)式生成WLRRegularExpression實例
- _regexMatcher = [WLRRegularExpression expressionWithPattern:_routeExpressionPattern];
- }
- return self;
- }
匹配方法:
- -(WLRRouteRequest *)createRequestWithURL:(NSURL *)URL primitiveParameters:(NSDictionary *)primitiveParameters targetCallBack:(void (^)(NSError *, id))targetCallBack{
- NSString * urlString = [NSString stringWithFormat:@"%@%@",URL.host,URL.path];
- if (self.scheme.length && ![self.scheme isEqualToString:URL.scheme]) {
- return nil;
- }
- //調(diào)用self.regexMatcher將URL傳入,獲取WLRMatchResult結(jié)果,看是否匹配
- WLRMatchResult * result = [self.regexMatcher matchResultForString:urlString];
- if (!result.isMatch) {
- return nil;
- }
- //如果匹配,則將result.paramProperties路徑參數(shù)傳入,初始化一個WLRRouteRequest實例
- WLRRouteRequest * request = [[WLRRouteRequest alloc]initWithURL:URL routeExpression:self.routeExpressionPattern routeParameters:result.paramProperties primitiveParameters:primitiveParameters targetCallBack:targetCallBack];
- return request;
- }
WLRRouter
- @class WLRRouteRequest;
- @class WLRRouteHandler;
- @interface WLRRouter : NSObject
- //注冊block回調(diào)的URL匹配表達(dá)式,可用作內(nèi)部調(diào)用
- -(void)registerBlock:(WLRRouteRequest *(^)(WLRRouteRequest * request))routeHandlerBlock forRoute:(NSString *)route;
- //注冊一個WLRRouteHandler對應(yīng)的URL匹配表達(dá)式route
- -(void)registerHandler:(WLRRouteHandler *)handler forRoute:(NSString *)route;
- //判斷url是否可以被handle
- -(BOOL)canHandleWithURL:(NSURL *)url;
- -(void)setObject:(id)obj forKeyedSubscript:(NSString *)key;
- -(id)objectForKeyedSubscript:(NSString *)key;
- //調(diào)用handleURL方法,傳入URL、原生參數(shù)和targetCallBack和完成匹配的completionBlock
- -(BOOL)handleURL:(NSURL *)URL primitiveParameters:(NSDictionary *)primitiveParameters targetCallBack:(void(^)(NSError *, id responseObject))targetCallBack withCompletionBlock:(void(^)(BOOL handled, NSError *error))completionBlock;
在實現(xiàn)部分,有三個屬性:
- //每一個URL的匹配表達(dá)式route對應(yīng)一個matcher實例,放在字典中
- @property(nonatomic,strong)NSMutableDictionary * routeMatchers;
- //每一個URL匹配表達(dá)式route對應(yīng)一個WLRRouteHandler實例
- @property(nonatomic,strong)NSMutableDictionary * routeHandles;
- //每一個URL匹配表達(dá)式route對應(yīng)一個回調(diào)的block
- @property(nonatomic,strong)NSMutableDictionary * routeblocks;
在Route掛在Handler和回調(diào)的block的時候:
- -(void)registerBlock:(WLRRouteRequest *(^)(WLRRouteRequest *))routeHandlerBlock forRoute:(NSString *)route{
- if (routeHandlerBlock && [route length]) {
- //首先添加一個WLRRouteMatcher實例
- [self.routeMatchers setObject:[WLRRouteMatcher matcherWithRouteExpression:route] forKey:route];
- //刪除route對應(yīng)的handler對象
- [self.routeHandles removeObjectForKey:route];
- //將routeHandlerBlock和route存入對應(yīng)關(guān)系的字典中
- self.routeblocks[route] = routeHandlerBlock;
- }
- }
- -(void)registerHandler:(WLRRouteHandler *)handler forRoute:(NSString *)route{
- if (handler && [route length]) {
- //首先生成route對應(yīng)的WLRRouteMatcher實例
- [self.routeMatchers setObject:[WLRRouteMatcher matcherWithRouteExpression:route] forKey:route];
- //刪除route對應(yīng)的block回調(diào)
- [self.routeblocks removeObjectForKey:route];
- //設(shè)置route對應(yīng)的handler
- self.routeHandles[route] = handler;
- }
- }
接下來完善handle方法:
以上我們可以看到,Route將匹配的邏輯單獨封裝到WLRRouteMatcher對象中,將匹配后的結(jié)果生成WLRRouteRequest實例以攜帶足夠完整的數(shù)據(jù),同時將真正處理視圖控制器的轉(zhuǎn)場或者是組件的加載或者是未來可能拓展的handle業(yè)務(wù)封裝到WLRRouteHandler實例中,匹配邏輯對應(yīng)的處理邏輯干凈分離,匹配邏輯可單獨塑造業(yè)務(wù)匹配,處理邏輯可以通過繼承擴展或者沖洗WLRRouteHandler的生命周期函數(shù)來更好的處理回調(diào)業(yè)務(wù)。如果WLRRouteHandler不能提供足夠多的擴展性,則可以使用block回調(diào)最大限度的進(jìn)行擴展。
以上,就是路由部分的整體實現(xiàn)。
轉(zhuǎn)場的擴展
在WLRRouteHandler中,其實我們可以單獨控制路由經(jīng)過的頁面跳轉(zhuǎn)的轉(zhuǎn)場。
- -(UIViewController *)targetViewControllerWithRequest:(WLRRouteRequest *)request{
- }
- -(UIViewController *)sourceViewControllerForTransitionWithRequest:(WLRRouteRequest *)request{
- }
- -(BOOL)transitionWithRequest:(WLRRouteRequest *)request error:(NSError *__autoreleasing *)error{
- }
這樣的生命周期函數(shù)是不是很像UIViewControllerContextTransitioning轉(zhuǎn)場上下文的協(xié)議的設(shè)定?- (nullable __kindof UIViewController *)viewControllerForKey:(UITransitionContextViewControllerKey)key;方法使上下文提供目標(biāo)控制器和源控制器,其實在handler中你完全可以自定義一個子類,在transitionWithRequest方法里,設(shè)置遵守UIViewControllerTransitioningDelegate的代理,然后在此提供遵守 UIViewControllerAnimatedTransitioning的動畫控制器,然后自定義轉(zhuǎn)場上下文,實現(xiàn)自定義UI轉(zhuǎn)場,而對應(yīng)的匹配邏輯是與此無關(guān)的,我們就可以在路由曾控制全局的頁面轉(zhuǎn)場效果。對自定義轉(zhuǎn)場不太熟悉的同學(xué)請移步我之前的文章:
ContainerViewController的ViewController 轉(zhuǎn)場
路由的安全
有兩個方面可以去做
- WLRRouteHandler實例中, -(BOOL)shouldHandleWithRequest:(WLRRouteRequest *)request中可以檢測request中的參數(shù),比方說效驗source或者是效驗業(yè)務(wù)參數(shù)完整等
- WLRRouter實例中handleURL方法,將在隨后的WLRRoute的0.0.2版本中加入中間件的支持,就是在找到handler之前,將按照中間件注冊的順序回調(diào)中間件,而我們可以在中間件中實現(xiàn)風(fēng)控業(yè)務(wù)、認(rèn)證機制、加密驗簽等等
路由的效率
目前我們實現(xiàn)的路由是一個同步阻塞型的,在處理并發(fā)的時候可能會出現(xiàn)一些問題,或者是在注冊比較多的route表達(dá)式以后,遍歷和匹配的過程會損耗性能,比較好的實現(xiàn)方式是,將Route修改成異步非阻塞型的,但是API全部要換成異步API,起步我們先把同步型的搞定,隨后慢慢提供異步版本的路由~
路由的使用
在大部分App實踐MVVM架構(gòu)或者更為復(fù)雜的VIPER架構(gòu)的時候,除了迫切需要一個比較解耦的消息傳遞機制,如何更好的剝離目標(biāo)實體的獲取和配合UIKit這一層的轉(zhuǎn)場邏輯是一項比較復(fù)雜的挑戰(zhàn),路由實際上是充當(dāng)MVVM的ViewModel中比較解耦的目標(biāo)獲取邏輯和VIPER中Router層,P與V的調(diào)用全部靠Router轉(zhuǎn)發(fā)。
在實施以組件化為目的的工程化改造中,如何抽離單獨業(yè)務(wù)為組件,比較好的管理業(yè)務(wù)與業(yè)務(wù)之間的依賴,就必須使用一個入侵比較小的Route,WLRRoute入侵的地方在于WLRRouteHandler的transitionWithRequest邏輯中,通過一個UIViewController的擴展,給 targetViewController.wlr_request = request;設(shè)置了WLRRouteRequest對象給目標(biāo)業(yè)務(wù),但雖然如此,你依舊可以重寫WLRRouteHandler的transitionWithRequest方法,來構(gòu)建你自己參數(shù)傳遞方式,這一點完全取決于你如何更好的使得業(yè)務(wù)無感知而使用路由。
最后附上代碼地址:
喜歡的來個星吧…
https://github.com/Neojoke/WLRRoute