序言
對于一款成熟的App來說,持續(xù)迭代帶來的功能膨脹,不同開發(fā)者的編碼習慣差異,必然導致代碼管理成為一大重要課題。如何更高效率地進行分工合作,如何在團隊需要的時候快速回滾代碼,這些都是需要研究的,在我看來,組件化便是對這些場景的一個良好解決方案。
組件化的優(yōu)缺點
組件化即是將代碼按照功能/場景拆分,做成不同的組件分別維護。
優(yōu)點:
- 代碼耦合少,方便維護
- 分工更明確,方便分配人員
- 靈活,組件可以在不同App中使用
- 回滾方便
缺點:
- 前期設計工作繁雜,不適合快速試錯場景
- 發(fā)版流程冗長,需要通過腳本配合
CocoaPods
CocoaPods是iOS上一個比較有名的類庫管理工具,絕大部分的開源庫都可以通過它來進行集成。另外,它也支持開發(fā)者自行創(chuàng)建私有庫來集成。業(yè)界常用的組件化方案即是使用CocoaPods來創(chuàng)建組件庫,然后集成。讓我們簡單看一下如何使用CocoaPods創(chuàng)建一個私有庫。
1.創(chuàng)建私有庫
新建一個lib文件夾,并且在該目錄下使用命令
pod lib create 私有庫名稱
然后跟隨著指示選擇符合自己情況的選項。

CocoaPods會在當前目錄下創(chuàng)建一個目錄BlogPart,在該目錄下有一個BlogPart.podspec文件,里面有著該私有庫的一些配置,內容如圖所示。

可以看到最后一行s.source_files的值,意味著私有庫的源文件全部來自于BlogPart/Classes目錄下。在該目錄中,可以找到有一個ReplaceMe.m的文件,把該文件刪除,并且把真正需要放入私有庫的文件放在此目錄下即可。
我在該目錄添加了BPViewController.h和BPViewController.m文件。
另外,在lib/BlogPart/Example目錄下有該私有庫的樣例工程,查看樣例工程目錄下的Podfile文件,可以看到pod庫的位置為../目錄下的BlogPart,即引用了剛剛創(chuàng)建的本地的私有庫路徑。

在樣例工程目錄執(zhí)行以下命令,即可將BlogPart私有庫添加到樣例工程中去。
pod install
可以看見工程中包含了BPViewController.h和BPViewController.m文件。

2.發(fā)布私有庫
首先在git上添加自己的私有倉庫

將整個BlogPart工程推送到該倉庫中,執(zhí)行以下命令。
git remote add origin 倉庫地址
git add .
git commit -a -m 'init'
git tag -a 0.1.0 -m 'init'
git push -u origin master
git push --tags
其中0.1.0為tag版本號,要與BlogPart.podspec中的s.version保持一致
將BlogPart.podspec中的s.source和s.homepage替換成對應該私有倉庫的地址,并且使用以下命令添加git私有倉庫。
pod repo add 私有庫名稱 倉庫地址
然后使用以下命令檢測私有庫是否滿足發(fā)布要求
pod spec lint 私有庫名稱.podspec
如果通過,則會顯示如下結果。

此時私有庫滿足發(fā)布要求,便可以按照以下步驟發(fā)布。
pod repo push 私有庫名稱 私有庫名稱.podspec
可以看到如下結果,表示發(fā)布成功

3.使用私有庫
創(chuàng)建一個iOS項目,并且使用命令
pod init
該項目會被轉化為一個包含CocoaPods的項目,編輯目錄下的Podfile文件。
添加相關的source
source 私有庫地址
在target下添加引入的pod庫
pod 'BlogPart','~> 0.1.0'
如圖所示

隨后在該目錄使用命令
pod install
打開項目即可看到之前創(chuàng)建的私有庫已被引入。

組件化思路
我們平時設計一個App時就會將各個業(yè)務模塊分開解耦,而組件化其實就是將這些模塊打包做成組件。
結構
一般而言,App的代碼可以分為五個部分,如圖所示。

通用服務組件
這一部分一般存放一些IO、數據庫讀寫、網絡傳輸等代碼。通用UI組件
這一部分一般存放一些不涉及具體業(yè)務的通用UI控件,例如按鈕、單選控件等。業(yè)務組件
這一部分一般存放涉及到具體業(yè)務的UI控件、以及調用通用UI組件和通用服務組件的代碼。
這一部分根據實際情況,可能會再分一層。基礎框架組件
這一部分一般存放App中用到的各種容器類,處理模塊之間切換的交互,通信等。App
這一部分負責處理業(yè)務與容器類的關系。
按照這樣的分層方式,各個組件各司其職,代碼條理就會更加清晰透徹,容易維護。
如果想要改變整個App的結構,只需要去修改基礎架構部分和App部分。
如果想要改變某個業(yè)務的邏輯,只需要更改業(yè)務部分。
如果想要改變整體的風格,改變部分控件的樣式,只需要修改通用UI組件。
如果想要底層某個通信協(xié)議需要更改,也只需要修改通用服務組件即可。
通信
不過就如前文提到的,分層越多,組件之間的通信、交互就是一個很大的問題,一旦設計的不好,不僅是修復Bug的時候追溯源頭困難,本身開發(fā)效率也會十分低下。
我嘗試過以下三種通信方案。
各個組件通過Block或者Protocol來與高層組件進行交互。
此方案需要大量代碼來制定不同場景需要的不同規(guī)則。各個組件通過Notification的方式來與高層組件進行交互。
此方案維護Notification表上會花費較多時間,并且Notification沒有編譯器檢測。將部分接口下沉到下層,通信全部通過調用下層接口,實際實現(xiàn)通過上層組件的Category來替換。
此方案需要的代碼較少,但是容易發(fā)生一些Category相互替換導致的Bug。
每個方案都各有利弊,實際開發(fā)還是需要權衡實際情況進行選擇。
總結
iOS組件化可以拿出來深挖的東西太多了,限于篇幅的局限,本文僅作拋磚引玉用。