1. 程式人生 > >iOS元件化方案對比

iOS元件化方案對比

背景

隨著公司業務的不斷髮展,專案的功能越來越複雜,各個業務程式碼耦合也越來越多,程式碼量也是急劇增加,傳統的MVC或者MVVM架構已經無法高效的管理工程程式碼,因此需要用一種技術來更好地管理工程,而元件化是一種能夠解決程式碼耦合的技術。專案經過元件化的拆分,不僅可以解決程式碼耦合的問題,還可以增強程式碼的複用性,工程的易管理性等等。

市場上的方案:

方案一、url-block

這是蘑菇街中應用的一種頁面間呼叫的方式,通過在啟動時註冊元件提供的服務,把呼叫元件使用的`url`和元件提供的服務`block`對應起來,儲存到記憶體中。在使用元件的服務時,通過`url`找到對應的`block`,然後獲取服務。

下圖是`url-block`的架構圖:

註冊:

[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"]

優點:

  1. h5外跳到蘑菇街app,app內部的h5和app的原生互動,都可以直接使用這些定義好的路由。

  2. 蘑菇街為了統一iOSAndroid的平臺差異性,專門用後臺來管理url,然後針對不同的平臺,生成不同型別的檔案,來方便使用。

缺點:

  1. 需要在記憶體中維護url-block的表,元件多了可能會有記憶體問題。

  2. url的引數傳遞受到限制,只能傳遞常規的字串引數,無法傳遞非常規引數,如UIImageNSData等型別。

  3. 沒有區分本地呼叫和遠端呼叫的情況,尤其是遠端呼叫,會因為url引數受限,導致一些功能受限。

  4. 元件本身依賴了中介軟體,且分散註冊使的耦合較多。

  5. url註冊對於實施元件化是完全沒有必要的,查詢 URL 的實現不夠高效。

  6. 路由寫錯後編譯沒問題,而實現執行就出問題了,以後維護也不方便。

方案二、protocol-class

針對方案一的問題,蘑菇街又提出了另一種元件化的方案,就是通過protocol定義服務介面,元件通過實現該介面來提供介面定義的服務,具體實現就是把protocolclass做一個對映,同時在記憶體中儲存一張對映表,使用的時候,就通過protocol找到對應的class來獲取需要的服務。

下圖是protocol-class的架構圖:

註冊:

[ModuleManager registerClass:ClassA forProtocol:ProtocolA]

呼叫:

[ModuleManager classForProtocol:ProtocolA]

優點:

  1. 蘑菇街的這種方案確實解決了方案一中無法傳遞非常規引數的問題。

  2. 元件間的呼叫更為方便。

  3. 解耦程式碼量少,實現方便,以後維護也方便。

  4. 協議方法改變後,編譯就會報錯,避免程式碼修改遺漏。

  5. 協議方法未實現的話,會報編譯警告。

  6. 方法查詢容易,呼叫高效。

缺點:

  1. 元件的方法呼叫分散。

  2. 記憶體中維護對映表。

  3. 協議方法有可能未實現。

  4. 對元件協議需要註冊,不註冊就無法呼叫。

方案三、url-controller

這是LDBusMediator的元件化方案,它是通過元件實現公共協議的服務,來對外提供服務。具體就是通過單例來維護url-controller的對映關係表,根據呼叫者的url,以及提供的引數(字典型別,所以引數型別不受約束)來返回對應的controller來提供服務;同時,為了增強元件提供服務的多樣性,又通過服務協議定義了其它的服務。

優點:

  1. LDBusMediator解決了蘑菇街的這兩種元件化方案的不足,比如:通過註冊封裝件connector而不是block來降低了記憶體佔用。

  2. 通過字典傳遞引數,解決了url引數的限制性。

缺點:

  1. 記憶體中維護對映表。

  2. 元件本身依賴了中介軟體,且分散註冊使的耦合較多。

  3. url註冊對於實施元件化是完全沒有必要的,查詢 URL 的實現不夠高效。

  4. 路由寫錯後編譯沒問題,而實現執行就出問題了,以後維護也不方便。

方案四、target-action

通過給元件包裝一層wrapper來給外界提供服務,然後呼叫者通過依賴中介軟體來使用服務;其中,中介軟體是通過runtime來呼叫元件的服務,是真正意義上的解耦,也是該方案最核心的地方。具體實施過程是給元件封裝一層target物件來對外提供服務,不會對原來元件造成入侵;然後,通過實現中介軟體的category來提供服務給呼叫者,這樣使用者只需要依賴中介軟體,而元件則不需要依賴中介軟體。

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

優點:

  1. 記憶體中不需要維護對映表。

  2. 不需要註冊。

缺點:

  1. 中介軟體實現繁瑣。

  2. 中介軟體方法型別、引數、返回值不夠靈活。

  3. 中介軟體方法內部使用字串來呼叫方法和類,呼叫死板。

  4. 中介軟體方法內部容易寫錯,寫錯後編譯沒問題,而實現執行就出問題了,以後維護也不方便。

方案五、Extension和Category結合使用

東方財富浪客直播的不同元件控制器跳轉使用了這種方式,這個方式是我以前想出來的。在基礎元件定義一個UIViewController 的Extension和Category,Extension裡面封裝各種元件間控制器跳轉的呼叫方法,這裡面沒有實現,Category裡面也和Extension對應封裝相應方法,Category有實現,內部是呼叫的Extension封裝的方法,呼叫時先判斷Extension的方法有沒有實現,做下保護。元件控制器跳轉呼叫Category封裝的方法。元件負責實現Extension定義的方法。

當然這種方案不只適用於控制器跳轉,還可以改造成NSObject 的Extension和Category,適應所有的元件間通訊。

Extension方法定義:

Category方法定義:

Category方法實現:

Extension方法實現:

優點:

  1. Category實現內部做了Extension方法是否實現的判斷,避免了不實現出現的崩潰

  2. 確實解決了方案一中無法傳遞非常規引數的問題

  3. 元件間的呼叫方便。

  4. 協議方法改變後,編譯就會報錯,避免程式碼修改遺漏。

  5. 記憶體中不需要維護對映表。

缺點:

  1. Extension和Category都定義了同樣的方法,相比protocol-class方案不夠簡潔。

  2. 方法為了避免衝突,都要加字首。

總結:

元件化是專案架構層面的技術,不是所有專案都適合元件化,元件化一般針對的是大中型的專案,並且是多人開發。如果,專案比較小,開發人員比較少,確實不太適合元件化,因為這時的元件化可能帶來的不是便捷,而是增加了開發的工作量。另外,元件化過程也要考慮團隊的情況,總之,根據目前專案的情況作出最合適的技術選型。沒有最好的技術,只有最合適的技術。