ios业务模块间互相跳转的解耦方案
*此文章需有一點(diǎn)runtime的知識,假設(shè)你不了解runtime,《高速理解Runtime of Objective-C》:
http://mp.weixin.qq.com/s?__biz=MzIxNDI0OTAzOQ==&mid=403005635&idx=1&sn=71375cb0dee51487c90087d488ff59fe#rd
問題:
一個(gè)app通常由很多個(gè)模塊組成,全部模塊之間免不了會相互調(diào)用,比如一個(gè)讀書管理軟件,可能會有書架、用戶信息、圖書詳情等等模塊,從用戶信息-我讀的書中,能夠打開圖書詳情。而在圖書詳情-所在書架,又能夠打開書架。
一般這樣的需求我們可能會這實(shí)現(xiàn):
/*用戶信息模塊*/ #import "UserViewController.h" #import "BookDetailViewController.h"@implementation UserViewController //跳轉(zhuǎn)到圖書詳情 + (void)gotoBookDetail {BookDetailViewController *detailVC = [[BookDetailViewController alloc] initWithBookId:self.bookId];[self.navigationController.pushViewController:detailVC animated:YES]; } @end
項(xiàng)目初期還好,速度快,夠簡單。可是項(xiàng)目發(fā)展到一定程度時(shí),問題就來了,每一個(gè)模塊都離不開其它模塊,互相依賴粘在一起:
圖1:模塊依賴關(guān)系。箭頭方向表示依賴,比方:Discover依賴BookDetail
解決方式:
遇到這樣的情況,最直接的方法就是添加一個(gè)中間件,各個(gè)模塊跳轉(zhuǎn)通過中間件來管理。這樣。全部模塊僅僅依賴這個(gè)中間件。可是中間件怎么去調(diào)用其它模塊那?好吧,中間件又會依賴全部模塊。
好像除了添加代碼的復(fù)雜度,并沒有真正解決不論什么問題。
引入中間件的代碼:
/*用戶信息模塊*/ #import "UserViewController.h" #import "Mediator.h”@implementation UserViewController //跳轉(zhuǎn)到圖書詳情 + (void)gotoBookDetail {[Mediator gotoBookDetail:self.bookId]; } @end/*中間件*/ #import “Mediator.h” #import “BookDetailViewController.h"@implementation Mediator //跳轉(zhuǎn)到圖書詳情 + (void)gotoBookDetail:(NSString *)bookid {BookDetailViewController *detailVC = [[BookDetailViewController alloc] initWithBookId:bookId];[self.navigationController.pushViewController:detailVC animated:YES]; } @end
引入中間件的依賴關(guān)系:
圖2:引入中間件的依賴關(guān)系
有沒有一種方法,能夠完美的解決這個(gè)依賴關(guān)系那?我們希望做到:每一個(gè)模塊之間互相不依賴,而且每一個(gè)模塊能夠脫離project由不同的人編寫、單獨(dú)編譯調(diào)試。以下的方案通過對中間件的改造,非常好的攻克了這個(gè)問題,解決后的模塊間依賴關(guān)系例如以下:
圖3: 比較理想的模塊間依賴關(guān)系
實(shí)現(xiàn)方法:
我們通過一個(gè)實(shí)際的樣例來分析一下。
請先下載demo并打開:https://github.com/zcsoft/ZC_CTMediator
先看一下文件夾結(jié)構(gòu),對整個(gè)project的組織結(jié)構(gòu)有一個(gè)大致的了解,然后結(jié)合后面的結(jié)構(gòu)圖和每一個(gè)類的說明、以及project代碼,來詳細(xì)分析詳細(xì)實(shí)現(xiàn):
文件夾結(jié)構(gòu):
[CTMediatorproject文件夾]
|
|-[CTMediator]
|? ? ? ? |-CTMediator.h.m
|? ? ? ? |-[Categories]
|? ? ? ? ? ? ? ? |-[ModuleA]
|? ? ? ? ? ? ? ? ? ? ? ? |-CTMediator+CTMediatorModuleAActions.h.m
|
|-[DemoModule]
|? ? ? ? |-[Actions]
|? ? ? ? | ? ? ? |-Target_A.h.m
|? ? ? ? |-DemoModuleADetailViewController.h.m
|
|-AppDelegate.h.m
|-ViewController.h.m
說明:
[CTMediator]
負(fù)責(zé)跳轉(zhuǎn)的中間件,全部模塊間跳轉(zhuǎn)都通過這個(gè)模塊來完畢。
[DemoModule]
一個(gè)樣例模塊。假設(shè)我們要從其它業(yè)務(wù)(ViewController.h.m)中跳轉(zhuǎn)到這個(gè)業(yè)務(wù)模塊。
在這個(gè)demo中,我們的目的是從其它業(yè)務(wù)(ViewController.h.m中)跳轉(zhuǎn)到DemoModule業(yè)務(wù)模塊。
全部模塊的引用關(guān)系如圖:
圖4:demo中個(gè)模塊的引用關(guān)系
?
因?yàn)閐emo中僅僅是從ViewController.h.m中跳轉(zhuǎn)到DemoModule模塊。所以僅僅須要ViewController.h.m依賴CTMediator,CTMediator到DemoModule模塊的調(diào)用是使用執(zhí)行時(shí)完畢了(圖片中的藍(lán)線),在代碼中不須要相護(hù)依賴。也就是說。假設(shè)一個(gè)模塊不須要跳轉(zhuǎn)到其它模塊。就不須要依賴CTMediator。
執(zhí)行時(shí)的時(shí)序:
圖5:隱藏了模塊內(nèi)實(shí)現(xiàn)細(xì)節(jié)的引用關(guān)系
調(diào)用關(guān)系概述:
首先由ViewController.h.m發(fā)起調(diào)用請求給CTMediator。CTMediator通過runtime去調(diào)用目標(biāo)模塊DemoModule,目標(biāo)模塊DemoModule依據(jù)參數(shù)創(chuàng)建自己的一個(gè)實(shí)例。并把這個(gè)實(shí)例返回給CTMediator。CTMediator在把這個(gè)實(shí)例返回給ViewController.h.m(此時(shí)ViewController.h.m不須要知道這個(gè)實(shí)例的詳細(xì)類型,僅僅須要知道是UIViewController的子類),然后由ViewController.h.m決定以什么樣的方式去展示DemoModule。
圖6: 完整的調(diào)用關(guān)系
調(diào)用關(guān)系詳細(xì)解釋:
1: ViewController.m發(fā)起調(diào)用請求給CTMediator(CTMediator+CTMediatorModuleAActions.m)。
ViewController.m-57行
2: CTMediator+CTMediatorModuleAActions.m通過定義好的參數(shù)調(diào)用CTMediator。因?yàn)镃TMediator+CTMediatorModuleAActions是CTMediator的擴(kuò)展,所以能夠直接使用self來調(diào)用CTMediator的實(shí)現(xiàn)。CTMediator+CTMediatorModuleAActions.m-行23
UIViewController *viewController =[self performTarget:kCTMediatorTargetAaction:kCTMediatorActionNativFetchDetailViewControllerparams:@{@"key":@"value"}];3: CTMediator依據(jù)CTMediator+CTMediatorModuleAActions.m傳過來的目標(biāo)和參數(shù)發(fā)起實(shí)際調(diào)用。這個(gè)調(diào)用關(guān)系是在執(zhí)行時(shí)完畢的。所以此處并不須要在代碼上依賴被調(diào)用者。假設(shè)被調(diào)用者不存在,也能夠在執(zhí)行時(shí)進(jìn)行處理。CTMediator.m-93行
return [target performSelector:action withObject:params];
4/5: Target_A創(chuàng)建一個(gè)DemoModuleADetailViewController類型的實(shí)例(這個(gè)實(shí)例是Target_A通過DemoModuleADetailViewController類的alloc/init創(chuàng)建的)。Target_A.m-20行
6: Target_A返回創(chuàng)建的實(shí)例到CTMediator.m(發(fā)起時(shí)是通過runtime,步驟3),返回后CTMediator.m并不知道這個(gè)實(shí)例的詳細(xì)類型,也不會對這個(gè)類進(jìn)行不論什么解析操作,所以CTMediator.m跟返回的實(shí)例之間是沒有不論什么引用關(guān)系的。
Target_A.m-23行
7: CTMediator.m返回步驟6中得到的實(shí)例到CTMediator+CTMediatorModuleAActions.m(發(fā)起時(shí)是步驟2)。CTMediator.m-93行
8: CTMediator+CTMediatorModuleAActions.m會將步驟7返回的實(shí)例當(dāng)作UIViewController處理。接下來會在執(zhí)行時(shí)推斷這個(gè)實(shí)例的類型是不是UIViewController(是不是UIViewController的子類)。然后將得到的UIViewController交給調(diào)用者ViewController.m(由ViewController.m負(fù)責(zé)以何種方式進(jìn)行展示)。
CTMediator+CTMediatorModuleAActions.m-行29
全部類的功能例如以下:
CTMediator.h.m
功能:指定目標(biāo)(target。類名)+動作(action,方法名)。并提供一個(gè)字典類型的參數(shù)。CTMediator.h.m會推斷target-action能否夠調(diào)用,假設(shè)能夠。則調(diào)用。因?yàn)檫@一功能是通過runtime動態(tài)實(shí)現(xiàn)的,所以在CTMediator.h.m的實(shí)現(xiàn)中。不會依賴不論什么其它模塊,也不須要知道target-action的詳細(xì)功能,僅僅要target-action存在。就會被執(zhí)行(target-action詳細(xì)的功能由DemoModule自己負(fù)責(zé))。
CTMediator.h里實(shí)際提供了兩個(gè)方法,分別處理url方式的調(diào)用和target-action方式的調(diào)用。當(dāng)中,假設(shè)使用url方式,會自己主動把url轉(zhuǎn)換成target-action。
CTMediator+CTMediatorModuleAActions.h.m
功能:CTMediator的擴(kuò)展,用于管理跳轉(zhuǎn)到DemoModule模塊的動作。
其它模塊想要跳轉(zhuǎn)到DemoModule模塊時(shí)。通過調(diào)用這個(gè)類的方法來實(shí)現(xiàn)。
可是這個(gè)類中。并不真正去做跳轉(zhuǎn)的動作,它僅僅是對CTMediator.h.m類的封裝,這樣用戶就不須要關(guān)心使用CTMediator.h.m跳轉(zhuǎn)到DemoModule模塊時(shí)詳細(xì)須要的target名稱和action名稱了。
‘CTMediator.h.m’+‘CTMediator+CTMediatorModuleAActions.h.m’共同組成了一個(gè)面相DemoModule的跳轉(zhuǎn),而且它不會在代碼上依賴DemoModule,DemoModule是否提供了對應(yīng)的跳轉(zhuǎn)功能,僅僅體如今執(zhí)行時(shí)能否夠正常跳轉(zhuǎn)。至此,CTMediator這個(gè)中間層實(shí)現(xiàn)了全然的獨(dú)立,其它模塊不須要預(yù)先注冊。CTMediator也不須要知道其它模塊的實(shí)現(xiàn)細(xì)節(jié)。唯一的關(guān)聯(lián)就是須要在‘CTMediator+CTMediatorModuleAActions.h.m’中寫明正確的target+action和正確的參數(shù),而且這些action和參數(shù)僅僅依賴于Target_A.h.m。action和參數(shù)的正確性僅僅會在執(zhí)行時(shí)檢查。假設(shè)target或action不存在。能夠在‘CTMediator.h.m’中進(jìn)行對應(yīng)的處理。
既:CTMediator不須要依賴不論什么模塊就能夠編譯執(zhí)行。
Target_A.h.m
提供了跳轉(zhuǎn)到DemoModule模塊的對外接口,與CTMediator+CTMediatorModuleAActions.h.m相互對應(yīng),能夠說它僅僅用來為CTMediator+CTMediatorModuleAActions.h.m提供服務(wù),所以在實(shí)現(xiàn)CTMediator+CTMediatorModuleAActions.h.m時(shí)僅僅須要參考Target_A.h.m就可以,足夠簡單以至于并不須要文檔來輔助描寫敘述。其它模塊想跳轉(zhuǎn)到這個(gè)模塊時(shí),不能直接通過Target_A.h.m實(shí)現(xiàn)。而是要通過CTMediator+CTMediatorModuleAActions.h.m來完畢。
這樣,就實(shí)現(xiàn)了模塊間相互不依賴,而且僅僅有須要跳轉(zhuǎn)到其它模塊的地方,才須要依賴CTMediator。
DemoModuleADetailViewController.h.m
DemoModule模塊的主視圖,這個(gè)樣例中。會從ViewController.h.m跳轉(zhuǎn)到這個(gè)模塊。
AppDelegate.h.m
APP入口,從應(yīng)用外通過Scheme跳入程序時(shí)會經(jīng)過這個(gè)類。
ViewController.h.m
APP主視圖,須要在這里跳轉(zhuǎn)到DemoModule模塊。
@轉(zhuǎn)載請包涵以下全部信息
參考資料:
1: 方案來自:http://casatwy.com/iOS-Modulization.html?hmsr=toutiao.io&utm_medium=toutiao.io&utm_source=toutiao.io
感興趣的前往閱讀原文。
2: 本文同一時(shí)候也參考了:http://blog.cnbang.net/tech/3080/
歡迎大家關(guān)注我:iDevShare
或加我微信:lofocus
轉(zhuǎn)載于:https://www.cnblogs.com/yangykaifa/p/7106692.html
總結(jié)
以上是生活随笔為你收集整理的ios业务模块间互相跳转的解耦方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab语言中的assert断言函数
- 下一篇: Kafka 基本原理