iOS組件化方案的幾種實現

最近研究了一下項目的組件化,把casabanglimboy的有關組件化的博客看了一遍,學到了很多東西,對目前業界的組件化方案有了必定的瞭解。這些高質量的博客大體討論了組件化的三種方案:url-blockprotocol-class(和url-controller相似)、target-action,以及應用這三種組件化方案的時機、步驟、利弊等等。html

本文主要介紹一下這三種組件化方案的技術實現過程,針對不一樣組件化方案具體應用過程當中可能出現的問題加以介紹,也針對casa批判蘑菇街的組件化方案加以本身的思考,但願對須要瞭解組件化的朋友有必定的幫助。git

爲何須要組件化

隨着公司業務的不斷髮展,項目的功能愈來愈複雜,各個業務代碼耦合也愈來愈多,代碼量也是急劇增長,傳統的MVC或者MVVM架構已經沒法高效的管理工程代碼,所以須要用一種技術來更好地管理工程,而組件化是一種可以解決代碼耦合的技術。項目通過組件化的拆分,不只能夠解決代碼耦合的問題,還能夠加強代碼的複用性,工程的易管理性等等。github

組件化的過程

以前根據蘑菇街的組件化方案,limboycasa等人作了深刻的討論,並根據各自的觀點給出了方案實施的理由以及利弊關係,而後又有人改進了他們的組件化方案,我總結了一下,大體有三種,下面分別介紹各自的實現過程:架構

方案1、url-block

這是蘑菇街中應用的一種頁面間調用的方式,經過在啓動時註冊組件提供的服務,把調用組件使用的url和組件提供的服務block對應起來,保存到內存中。在使用組件的服務時,經過url找到對應的block,而後獲取服務。app

下圖是url-block的架構圖:模塊化

圖1

註冊:工具

[MGJRouter registerURLPattern:@"mgj://detail?id=:id" toHandler:^(NSDictionary *routerParameters) {
    NSNumber *id = routerParameters[@"id"];
    // create view controller with id
    // push view controller
}];

調用:組件化

[MGJRouter openURL:@"mgj://detail?id=404"]

蘑菇街爲了統一iOSAndroid的平臺差別性,專門用後臺來管理url,而後針對不一樣的平臺,生成不一樣類型的文件,來方便使用。ui

使用url-block的方案的確能夠組建間的解耦,可是仍是存在其它明顯的問題,好比:url

  1. 須要在內存中維護url-block的表,組件多了可能會有內存問題
  2. url的參數傳遞受到限制,只能傳遞常規的字符串參數,沒法傳遞很是規參數,如UIImageNSData等類型
  3. 沒有區分本地調用和遠程調用的狀況,尤爲是遠程調用,會由於url參數受限,致使一些功能受限
  4. 組件自己依賴了中間件,且分散註冊使的耦合較多

方案2、protocol-class

針對方案一的問題,蘑菇街又提出了另外一種組件化的方案,就是經過protocol定義服務接口,組件經過實現該接口來提供接口定義的服務,具體實現就是把protocolclass作一個映射,同時在內存中保存一張映射表,使用的時候,就經過protocol找到對應的class來獲取須要的服務。

下圖是protocol-class的架構圖:

圖2

註冊:

[ModuleManager registerClass:ClassA forProtocol:ProtocolA]

調用:

[ModuleManager classForProtocol:ProtocolA]

蘑菇街的這種方案確實解決了方案一中沒法傳遞很是規參數的問題,使得組件間的調用更爲方便,可是它依然沒有解決組件依賴中間件的問題、內存中維護映射表的問題、組件的分散調用的問題。設計思想和方案一相似,都是經過給組件加了一層wrapper,而後給使用者調用。

同時,另外一種方案是url-controller,這是LDBusMediator的組件化方案,我認爲和方案二的實現原理相似。它是經過組件實現公共協議的服務,來對外提供服務。具體就是經過單例來維護url-controller的映射關係表,根據調用者的url,以及提供的參數(字典類型,因此參數類型不受約束)來返回對應的controller來提供服務;同時,爲了加強組件提供服務的多樣性,又經過服務協議定義了其它的服務。總體來看,LDBusMediator解決了蘑菇街的這兩種組件化方案的不足,好比:經過註冊封裝件connector而不是block來下降了內存佔用;經過字典傳遞參數,解決了url參數的限制性。可是,因爲使用了connector來提供服務而不是組件自己,把connector做爲組件的一部分,依然有組件依賴中間件的問題。

下圖是LDBusMediator的組件化架構圖:

圖3

方案3、target-action

casa的方案是經過給組件包裝一層wrapper來給外界提供服務,而後調用者經過依賴中間件來使用服務;其中,中間件是經過runtime來調用組件的服務,是真正意義上的解耦,也是該方案最核心的地方。具體實施過程是給組件封裝一層target對象來對外提供服務,不會對原來組件形成入侵;而後,經過實現中間件的category來提供服務給調用者,這樣使用者只須要依賴中間件,而組件則不須要依賴中間件。

下圖是casa的組件化方案架構圖:

圖4

如下代碼來自casa的組件化demo

target

A組件

// TargetA.h

- (UIViewController *)Action_nativeFetchDetailViewController:(NSDictionary *)params;

CTMediator分類

// CTMediator+CTMediatorModuleAActions.h

- (UIViewController *)CTMediator_viewControllerForDetail;

// CTMediator+CTMediatorModuleAActions.m

- (UIViewController *)CTMediator_viewControllerForDetail
{
    return [self performTarget:kCTMediatorTargetA action:kCTMediatorActionNativFetchDetailViewController params:@{@"key":@"value"} shouldCacheTarget:NO];
}

調用

// ViewController.h
#import "CTMediator+CTMediatorModuleAActions.h"

[self presentViewController:[[CTMediator sharedInstance] CTMediator_viewControllerForDetail] animated:YES completion:nil];

從以上代碼能夠看出,使用者只須要依賴中間件,而中間件又不依賴組件,這是真正意義上的解耦。可是casa的這個方案有個問題就是hardcode,在中間件的category裏有hardcodecasa的解釋是在組件間調用時,最好是去model化,因此不可避免的引入了hardcode,而且全部的hardcode只存在於分類中。針對這個問題,有人提議,把全部的model作成組件化下沉,而後讓全部的組件均可以自由的訪問model,不過在我看來,這種方案雖然解決了組件間傳遞model的依賴問題,可是爲了解決這個小問題,直接把整個model層組件化後暴露給全部組件,容易形成數據泄露,付出的代價有點大。針對這個問題,通過和網友討論,一致以爲組件間調用時用字典傳遞數據,組件內調用時用model傳遞數據,這樣即減小組件間數據對model的耦合,又方便了組件內使用model傳遞數據的便捷性。

組件化實施的方式

組件化能夠利用git的源代碼管理工具的便利性來實施,具體就是創建一個項目工程的私有化倉庫,而後把各個組件的podspec上傳到私有倉庫,在須要用到組件時,直接從倉庫裏面取。

1.封裝公共庫和基礎UI庫

在具體的項目開發過程當中,咱們常會用到三方庫和本身封裝的UI庫,咱們能夠把這些庫封裝成組件,而後在項目裏用pod進行管理。其中,針對三方庫,最好再封裝一層,使咱們的項目部直接依賴三方庫,方便後續開發過程當中的更換。

2.獨立業務模塊化

在開發過程當中,對一些獨立的模塊,如:登陸模塊、帳戶模塊等等,也能夠封裝成組件,由於這些組件是項目強依賴的,調用的頻次比較多。另外,在拆分組件化的過程當中,拆分的粒度要合適,儘可能作到組件的獨立性。同時,組件化是一個漸進的過程,不可能把一個完整的工程一會兒所有組件化,要分步進行,經過不停的迭代,來最終實現項目的組件化。

3.服務接口最小化

在前兩步都完成的狀況下,咱們能夠根據組件被調用的需求來抽象出組件對外的最小化接口。這時,就能夠選擇具體應用哪一種組件化方案來實施組件化了。

總結

組件化是項目架構層面的技術,不是全部項目都適合組件化,組件化通常針對的是大中型的項目,而且是多人開發。若是,項目比較小,開發人員比較少,確實不太適合組件化,由於這時的組件化可能帶來的不是便捷,而是增長了開發的工做量。另外,組件化過程也要考慮團隊的狀況,總之,根據目前項目的狀況做出最合適的技術選型。我一直尊崇,沒有最好的技術,只有最合適的技術。


實際上個人組件化經驗也不是不少,本文也是根據casalimboybang等的博客中的內容,作了簡要的分析,針對文中的不足之處,還望你們指出,共同進步。(文中圖片來自互聯網,版權歸原做者全部)

參考資料

iOS應用架構談 組件化方案

iOS組件化實踐方案-LDBusMediator煉就

iOS組件化思路-大神博客研讀和思考

iOS 組件化方案探索

蘑菇街 App 的組件化之路

蘑菇街 App 的組件化之路·續

相關文章
相關標籤/搜索