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