你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> ios業務模塊間互相跳轉的解耦方案

ios業務模塊間互相跳轉的解耦方案

編輯:IOS開發綜合

*此文章需有一點runtime的知識,如果你不了解runtime,《快速理解Runtime of Objective-C》:

http://mp.weixin.qq.com/s?__biz=MzIxNDI0OTAzOQ==&mid=403005635&idx=1&sn=71375cb0dee51487c90087d488ff59fe

問題:

一個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:引入中間件的依賴關系

有沒有一種方法,可以完美的解決這個依賴關系那?我們希望做到:每個模塊之間互相不依賴,並且每個模塊可以脫離工程由不同的人編寫、單獨編譯調試。下面的方案通過對中間件的改造,很好的解決了這個問題,解決後的模塊間依賴關系如下:

\

圖3: 比較理想的模塊間依賴關系

 

實現方法:

 

我們通過一個實際的例子來分析一下。

請先下載demo並打開:https://github.com/zcsoft/ZC_CTMediator

 

先看一下目錄結構,對整個工程的組織結構有一個大致的了解,然後結合後面的結構圖和每個類的說明、以及工程代碼,來詳細分析具體實現:

 

 

目錄結構:

 

[CTMediator工程目錄]

|-[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行

 

 

UIViewController *viewController = [[CTMediator sharedInstance] CTMediator_viewControllerForDetail];

 

 

2: CTMediator+CTMediatorModuleAActions.m通過定義好的參數調用CTMediator,由於CTMediator+CTMediatorModuleAActions是CTMediator的擴展,所以可以直接使用self來調用CTMediator的實現。CTMediator+CTMediatorModuleAActions.m-行23

 

UIViewController *viewController =
        [self performTarget:kCTMediatorTargetA
                     action:kCTMediatorActionNativFetchDetailViewController
                     params:@{@"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行

 

 

DemoModuleADetailViewController *viewController = [[DemoModuleADetailViewController alloc] init];

 

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. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved