我們要堅信絕大部分問題,其他人早就遇到過,并且很可能有絕佳的解決方案,即使沒有,至少別人踩過的坑,我們不必再踩一次。所以對于組件化,也是一樣,我們要避免重復造輪子。于是,第一件事我們要做的就是找這個輪子。
iOS的兩個輪子:
(1)Limboy(蘑菇街)的組件化方案:
http://limboy.me/ios/2016/03/10/mgj-components.html
http://limboy.me/ios/2016/03/14/mgj-components-continued.html
(2)Casa(天貓)的組件化方案:
http://casatwy.com/iOS-Modulization.html
這兩組文章可以結合著看,非常有意思,另外底下評論的內容更精彩,有點像兩個高手在擂臺上切磋,底下有一堆圍觀助威點贊的。
文章自己看就好,很長,內容很豐富,甚至Casa還寫了一個Demo來論證自己的觀點,我們去粗取精,深入分析一下:
英雄所見略同:
我們先看看兩個同學意見相同的地方:
- 組件間的通訊涉及到傳參問題,那么這個參數首先需要去Model化,否則調用者和被調用者都需要持有Model的引用,達不到解耦的目的。
(去Model化會帶來一個問題,就是參數需要以NSDcitionary的方式傳遞,勢必會影響開發效率,因為調用雙方需要約定好各種Key,以及Key有問題時能夠準確拋出相關的異常) - 組件間通訊的參數需要分為常規(能夠使用JSON進行序列化的對象)和非常規。
- 對于遠程APP調用,都使用openUrl的方式(這個算是廢話,蘋果只支持這個),并且過程基本一致:openUrl-> parse-> target-action
求同存異
再看看兩個同學意見相左的地方:
- 發現服務:
Limboy采用應用初始化,各個組件向ModuleManager注冊的方式。
Casa采用iOS runtime機制,使用Mediator+target-action方式自動發現服務,免注冊化。 - 組件間通訊問題:
Limbo的方案,對于常規參數,使用openUrl方式,非常規參數使用注冊protocol的方式,通過publicProtocol暴露出需的類和方法,所有組件持有這個publicProtocol。
Casa的方案,分為遠程調用和本地調用,遠程調用的方式是openUrl方式,本地調用采用target-action方式,通過category將方法暴露出去,省去了注冊的這一步。 - 調用組件頁面的細節:
Limbo的方案是:調用者傳入相關參數發起調用 -> 響應方收到調用 -> 響應方創建頁面實例并pushViewController。
[MGJRouter registerURLPattern:@"mgj://detail?id=:id" toHandler:^(NSDictionary *routerParameters) {
NSNumber *id = routerParameters[@"id"];
// create view controller with id
// push view controller
}];
Casa的方案是:調用者傳入相關參數發起調用 -> 響應方收到調用 -> 響應方創建頁面實例并返回 -> 調用方拿到實例后進行處理。
我們可以看到Limboy方案的好處是:調用方不需要關心響應方的邏輯,只需要正確調用方法和傳遞參數即可,缺點是不夠靈活,如果調用方想Present而不是Push呢?而Casa的方案正好相反。
我個人更傾向Casa的方案,雖然代碼會長一些,但是清晰,對于這種跨組件的調用,清晰是第一位的,否則業務工程師很容易懵逼。
推薦另外一個同學bang(JSPatch的作者)的分析:http://blog.cnbang.net/tech/3080/