iOS組件化方案的幾種實現(xiàn)

最近研究了一下項目的組件化株旷,把casa朋魔、bang哀卫、limboy的有關組件化的博客看了一遍垮抗,學到了不少東西宵蕉,對目前業(yè)界的組件化方案有了一定的了解鲤脏。這些高質(zhì)量的博客大致討論了組件化的三種方案:url-block芬骄、protocol-class(和url-controller類似)寒矿、target-action蟆淀,以及應用這三種組件化方案的時機拯啦、步驟、利弊等等熔任。

本文主要介紹一下這三種組件化方案的技術實現(xiàn)過程褒链,針對不同組件化方案具體應用過程中可能出現(xiàn)的問題加以介紹,也針對casa批判蘑菇街的組件化方案加以自己的思考疑苔,希望對需要了解組件化的朋友有一定的幫助甫匹。

為什么需要組件化

隨著公司業(yè)務的不斷發(fā)展,項目的功能越來越復雜,各個業(yè)務代碼耦合也越來越多兵迅,代碼量也是急劇增加抢韭,傳統(tǒng)的MVC或者MVVM架構已經(jīng)無法高效的管理工程代碼,因此需要用一種技術來更好地管理工程恍箭,而組件化是一種能夠解決代碼耦合的技術刻恭。項目經(jīng)過組件化的拆分,不僅可以解決代碼耦合的問題扯夭,還可以增強代碼的復用性鳍贾,工程的易管理性等等。

組件化的過程

之前根據(jù)蘑菇街的組件化方案交洗,limboycasa等人做了深入的討論骑科,并根據(jù)各自的觀點給出了方案實施的理由以及利弊關系,然后又有人改進了他們的組件化方案藕筋,我總結了一下纵散,大致有三種梳码,下面分別介紹各自的實現(xiàn)過程:

方案一隐圾、url-block

這是蘑菇街中應用的一種頁面間調(diào)用的方式,通過在啟動時注冊組件提供的服務掰茶,把調(diào)用組件使用的url和組件提供的服務block對應起來暇藏,保存到內(nèi)存中。在使用組件的服務時濒蒋,通過url找到對應的block盐碱,然后獲取服務。

下圖是url-block的架構圖:

圖1

注冊:

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

調(diào)用:

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

蘑菇街為了統(tǒng)一iOSAndroid的平臺差異性沪伙,專門用后臺來管理url瓮顽,然后針對不同的平臺,生成不同類型的文件围橡,來方便使用暖混。

使用url-block的方案的確可以組建間的解耦,但是還是存在其它明顯的問題翁授,比如:

  1. 需要在內(nèi)存中維護url-block的表拣播,組件多了可能會有內(nèi)存問題
  2. url的參數(shù)傳遞受到限制,只能傳遞常規(guī)的字符串參數(shù)收擦,無法傳遞非常規(guī)參數(shù)贮配,如UIImageNSData等類型
  3. 沒有區(qū)分本地調(diào)用和遠程調(diào)用的情況塞赂,尤其是遠程調(diào)用泪勒,會因為url參數(shù)受限,導致一些功能受限
  4. 組件本身依賴了中間件,且分散注冊使的耦合較多

方案二酣藻、protocol-class

針對方案一的問題曹洽,蘑菇街又提出了另一種組件化的方案,就是通過protocol定義服務接口辽剧,組件通過實現(xiàn)該接口來提供接口定義的服務送淆,具體實現(xiàn)就是把protocolclass做一個映射,同時在內(nèi)存中保存一張映射表怕轿,使用的時候偷崩,就通過protocol找到對應的class來獲取需要的服務。

下圖是protocol-class的架構圖:

圖2

注冊:

[ModuleManager registerClass:ClassA forProtocol:ProtocolA]

調(diào)用:

[ModuleManager classForProtocol:ProtocolA]

蘑菇街的這種方案確實解決了方案一中無法傳遞非常規(guī)參數(shù)的問題撞羽,使得組件間的調(diào)用更為方便阐斜,但是它依然沒有解決組件依賴中間件的問題、內(nèi)存中維護映射表的問題诀紊、組件的分散調(diào)用的問題谒出。設計思想和方案一類似,都是通過給組件加了一層wrapper邻奠,然后給使用者調(diào)用笤喳。

同時,另一種方案是url-controller碌宴,這是LDBusMediator的組件化方案杀狡,我認為和方案二的實現(xiàn)原理類似。它是通過組件實現(xiàn)公共協(xié)議的服務贰镣,來對外提供服務呜象。具體就是通過單例來維護url-controller的映射關系表,根據(jù)調(diào)用者的url碑隆,以及提供的參數(shù)(字典類型恭陡,所以參數(shù)類型不受約束)來返回對應的controller來提供服務;同時上煤,為了增強組件提供服務的多樣性休玩,又通過服務協(xié)議定義了其它的服務。整體來看楼入,LDBusMediator解決了蘑菇街的這兩種組件化方案的不足哥捕,比如:通過注冊封裝件connector而不是block來降低了內(nèi)存占用;通過字典傳遞參數(shù)嘉熊,解決了url參數(shù)的限制性遥赚。但是,由于使用了connector來提供服務而不是組件本身阐肤,把connector作為組件的一部分凫佛,依然有組件依賴中間件的問題讲坎。

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

圖3

方案三、target-action

casa的方案是通過給組件包裝一層wrapper來給外界提供服務愧薛,然后調(diào)用者通過依賴中間件來使用服務晨炕;其中,中間件是通過runtime來調(diào)用組件的服務毫炉,是真正意義上的解耦瓮栗,也是該方案最核心的地方。具體實施過程是給組件封裝一層target對象來對外提供服務瞄勾,不會對原來組件造成入侵费奸;然后,通過實現(xiàn)中間件的category來提供服務給調(diào)用者进陡,這樣使用者只需要依賴中間件愿阐,而組件則不需要依賴中間件。

下圖是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];
}

調(diào)用

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

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

從以上代碼可以看出趾疚,使用者只需要依賴中間件缨历,而中間件又不依賴組件,這是真正意義上的解耦糙麦。但是casa的這個方案有個問題就是hardcode辛孵,在中間件的category里有hardcodecasa的解釋是在組件間調(diào)用時喳资,最好是去model化觉吭,所以不可避免的引入了hardcode腾供,并且所有的hardcode只存在于分類中仆邓。針對這個問題,有人提議伴鳖,把所有的model做成組件化下沉节值,然后讓所有的組件都可以自由的訪問model,不過在我看來榜聂,這種方案雖然解決了組件間傳遞model的依賴問題搞疗,但是為了解決這個小問題,直接把整個model層組件化后暴露給所有組件须肆,容易造成數(shù)據(jù)泄露匿乃,付出的代價有點大。針對這個問題豌汇,經(jīng)過和網(wǎng)友討論幢炸,一致覺得組件間調(diào)用時用字典傳遞數(shù)據(jù),組件內(nèi)調(diào)用時用model傳遞數(shù)據(jù)拒贱,這樣即減少組件間數(shù)據(jù)對model的耦合宛徊,又方便了組件內(nèi)使用model傳遞數(shù)據(jù)的便捷性佛嬉。

組件化實施的方式

組件化可以利用git的源代碼管理工具的便利性來實施,具體就是建立一個項目工程的私有化倉庫闸天,然后把各個組件的podspec上傳到私有倉庫暖呕,在需要用到組件時,直接從倉庫里面取苞氮。

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

在具體的項目開發(fā)過程中湾揽,我們常會用到三方庫和自己封裝的UI庫,我們可以把這些庫封裝成組件笼吟,然后在項目里用pod進行管理钝腺。其中,針對三方庫赞厕,最好再封裝一層艳狐,使我們的項目部直接依賴三方庫,方便后續(xù)開發(fā)過程中的更換皿桑。

2.獨立業(yè)務模塊化

在開發(fā)過程中毫目,對一些獨立的模塊,如:登錄模塊诲侮、賬戶模塊等等镀虐,也可以封裝成組件,因為這些組件是項目強依賴的沟绪,調(diào)用的頻次比較多刮便。另外,在拆分組件化的過程中绽慈,拆分的粒度要合適恨旱,盡量做到組件的獨立性。同時坝疼,組件化是一個漸進的過程搜贤,不可能把一個完整的工程一下子全部組件化,要分步進行钝凶,通過不停的迭代仪芒,來最終實現(xiàn)項目的組件化。

3.服務接口最小化

在前兩步都完成的情況下耕陷,我們可以根據(jù)組件被調(diào)用的需求來抽象出組件對外的最小化接口掂名。這時,就可以選擇具體應用哪種組件化方案來實施組件化了哟沫。

總結

組件化是項目架構層面的技術饺蔑,不是所有項目都適合組件化,組件化一般針對的是大中型的項目南用,并且是多人開發(fā)膀钠。如果掏湾,項目比較小,開發(fā)人員比較少肿嘲,確實不太適合組件化融击,因為這時的組件化可能帶來的不是便捷,而是增加了開發(fā)的工作量雳窟。另外尊浪,組件化過程也要考慮團隊的情況,總之封救,根據(jù)目前項目的情況作出最合適的技術選型拇涤。我一直尊崇,沒有最好的技術誉结,只有最合適的技術鹅士。


實際上我的組件化經(jīng)驗也不是很多,本文也是根據(jù)casa惩坑、limboy掉盅、bang等的博客中的內(nèi)容,做了簡要的分析以舒,針對文中的不足之處趾痘,還望大家指出,共同進步蔓钟。(文中圖片來自互聯(lián)網(wǎng)永票,版權歸原作者所有)

參考資料

iOS應用架構談 組件化方案

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

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

iOS 組件化方案探索

蘑菇街 App 的組件化之路

蘑菇街 App 的組件化之路·續(xù)

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市滥沫,隨后出現(xiàn)的幾起案子侣集,更是在濱河造成了極大的恐慌,老刑警劉巖佣谐,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肚吏,死亡現(xiàn)場離奇詭異方妖,居然都是意外死亡狭魂,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門党觅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來雌澄,“玉大人,你說我怎么就攤上這事杯瞻「湮” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵魁莉,是天一觀的道長睬涧。 經(jīng)常有香客問我募胃,道長,這世上最難降的妖魔是什么畦浓? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任痹束,我火速辦了婚禮,結果婚禮上讶请,老公的妹妹穿的比我還像新娘祷嘶。我一直安慰自己,他們只是感情好夺溢,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布论巍。 她就那樣靜靜地躺著,像睡著了一般风响。 火紅的嫁衣襯著肌膚如雪嘉汰。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天状勤,我揣著相機與錄音郑现,去河邊找鬼。 笑死荧降,一個胖子當著我的面吹牛接箫,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播朵诫,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼辛友,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了剪返?” 一聲冷哼從身側響起废累,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脱盲,沒想到半個月后邑滨,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡钱反,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年掖看,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片面哥。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡哎壳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出尚卫,到底是詐尸還是另有隱情归榕,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布吱涉,位于F島的核電站刹泄,受9級特大地震影響外里,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜特石,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一级乐、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧县匠,春花似錦风科、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至兰粉,卻和暖如春故痊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背玖姑。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工愕秫, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人焰络。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓戴甩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親闪彼。 傳聞我的和親對象是個殘疾皇子甜孤,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

推薦閱讀更多精彩內(nèi)容