iOS-底層原理 35:組件化(一)方案

iOS 底層原理 文章匯總

本文主要講解組件化的兩種方案

組件化

組件化其實(shí)就是將模塊單獨(dú)抽離寄狼、分層屿讽,并指定模塊間的通訊方式蚁趁,從而實(shí)現(xiàn)解耦的一種方式床估,主要運(yùn)用與團(tuán)隊(duì)開發(fā)

為什么需要組件化洲守?

主要有以下四個(gè)原因

  • 1焰轻、模塊間解耦

  • 2锄弱、模塊重用

  • 3锨亏、提高團(tuán)隊(duì)協(xié)作開發(fā)效率

  • 4、單元測(cè)試

當(dāng)項(xiàng)目因?yàn)楦鞣N需求纵诞,越來(lái)越來(lái)時(shí)上祈,如果此時(shí)的各個(gè)模塊之間是互相調(diào)用,即你中有我,我中有你這種情況時(shí)登刺,會(huì)造成高耦合的情況籽腕。一旦我們需要對(duì)某一塊代碼進(jìn)行修改時(shí),就會(huì)牽一發(fā)而動(dòng)全身纸俭,導(dǎo)致項(xiàng)目難以維護(hù)

其問(wèn)題主要體現(xiàn)在以下幾個(gè)方面:

  • 1皇耗、修改某個(gè)功能時(shí),同時(shí)需要修改其他模塊的代碼揍很,因?yàn)樵谄渌K中有該模塊的引用郎楼。可以理解為高耦合導(dǎo)致代碼修改困難

  • 2窒悔、模塊對(duì)外接口不明確呜袁,甚至暴露了本不該暴露的私有接口,修改時(shí)費(fèi)時(shí)費(fèi)力简珠〗捉纾可以理解為接口不固定導(dǎo)致的接口混亂

  • 3、高耦合代碼產(chǎn)生的后果就是會(huì)影響團(tuán)隊(duì)其他成員的開發(fā)聋庵,產(chǎn)生代碼沖突

  • 4膘融、當(dāng)模塊需要重用到其他項(xiàng)目時(shí),難以單獨(dú)抽離

  • 5祭玉、模塊間耦合的忌口導(dǎo)致接口和依賴關(guān)系混亂氧映,無(wú)法進(jìn)行單元測(cè)試

所以為了解決以上問(wèn)題,我們需要采用更規(guī)范的方式來(lái)降低模塊間的耦合度脱货,這就是組件化岛都,也可以理解為模塊化

但是,這里還需要說(shuō)明一點(diǎn)蹭劈,因?yàn)榻M件化也是需要一定成本的疗绣,需要花費(fèi)時(shí)間設(shè)計(jì)接口、分離代碼等铺韧,所以并不是所有的項(xiàng)目都需要組件化多矮。如果你的項(xiàng)目有以下這些特征就不需要組件化

  • 1、項(xiàng)目較小哈打,模塊間交互簡(jiǎn)單塔逃,耦合少

  • 2、項(xiàng)目沒有被多個(gè)外部模塊引用料仗,只是一個(gè)單獨(dú)的小模塊

  • 3湾盗、模塊不需要重用,代碼也很少被修改

  • 4立轧、團(tuán)隊(duì)規(guī)模很小

  • 5格粪、不需要編寫單元測(cè)試

如果你的有以下特性躏吊,說(shuō)明你就必須要考慮進(jìn)行組件化了:

  • 1、模塊邏輯復(fù)雜帐萎,多個(gè)模塊之間頻繁互相引用

  • 2比伏、項(xiàng)目規(guī)模逐漸變大,修改代碼變的越來(lái)越困難(這里可以理解為:修改一處代碼疆导,需要同時(shí)修改其他多個(gè)地方)

  • 3赁项、團(tuán)隊(duì)人數(shù)變多,提交的代碼經(jīng)常和其他成員沖突

  • 4澈段、項(xiàng)目編譯耗時(shí)較大

  • 5悠菜、模塊的單元測(cè)試經(jīng)常由于其他模塊的修改而失敗

組件化方案

組件化方案的8條指標(biāo)

一個(gè)項(xiàng)目經(jīng)過(guò)組件化后如何來(lái)評(píng)判,主要有以下幾個(gè)標(biāo)準(zhǔn)

  • 1败富、模塊之間沒有耦合悔醋,模塊內(nèi)部的修改不會(huì)應(yīng)該其他模塊
  • 2、模塊可以單獨(dú)編譯
  • 3囤耳、模塊間數(shù)據(jù)傳遞明確
  • 4篙顺、模塊可以隨時(shí)被另一個(gè)提供了相同功能的模塊替換
  • 5偶芍、模塊對(duì)外接口清晰且易維護(hù)
  • 6充择、當(dāng)模塊接口改變時(shí),此模塊的外部代碼能夠被高效重構(gòu)
  • 7匪蟀、盡量用最少的修改和代碼椎麦,讓現(xiàn)有的項(xiàng)目實(shí)現(xiàn)模塊化
  • 8、支持OC和Swift材彪,以及混編

前4條主要用于衡量一個(gè)模塊是否真正解耦观挎,后4條主要用于衡量在項(xiàng)目中實(shí)踐中的易用程度

組件化原則
一個(gè)項(xiàng)目主要分為3層:業(yè)務(wù)層通用層以及基礎(chǔ)層段化,在進(jìn)行組件化時(shí)嘁捷,有以下幾點(diǎn)說(shuō)明

組件化圖示

  • 只能上層對(duì)依賴,不能下層對(duì)上層的依賴显熏,因?yàn)橄聦邮菍?duì)上層的抽象

  • 項(xiàng)目公共代碼資源下沉

  • 橫向的依賴盡量少有雄嚣,最好下層至通用模塊,或者基礎(chǔ)模塊

組件化方案
常用的組件化方案主要有兩種:

  • 本地組件化:主要是通過(guò)在工程中創(chuàng)建library喘蟆,利用cocoapodsworkspec進(jìn)行本地管理缓升,不需要將項(xiàng)目上傳git,而是直接在本項(xiàng)目中以framework的方法進(jìn)行調(diào)用

  • cocoapods組件化:主要是利用cocoapods來(lái)進(jìn)行模塊的遠(yuǎn)程管理蕴轨,需要將項(xiàng)目上傳git(需要注意:這里的組件化模塊分為公有庫(kù)私有庫(kù)港谊,對(duì)公司而言,一般是私有庫(kù))

本地組件化

1橙弱、創(chuàng)建主工程

  • 首先創(chuàng)建一個(gè)工程


    工程結(jié)構(gòu)
  • 集成cocopods歧寺,進(jìn)行本地管理:

$ cd 項(xiàng)目目錄
$ pod init
  • 編輯podfile燥狰,并執(zhí)行pod install

2、創(chuàng)建組件

假設(shè)有以下幾個(gè)模塊:

  • 主工程:承載主要的表層業(yè)務(wù)代碼
  • Core:獨(dú)立存在斜筐,應(yīng)用加密碾局、接口請(qǐng)求等敏感代碼
  • Base:基類封裝,拓展奴艾,基本的數(shù)據(jù)處理
  • Service:服務(wù)層净当,封裝業(yè)務(wù)工具類,例如網(wǎng)絡(luò)層服務(wù)蕴潦、持久化服務(wù)等
  • Pods:三方依賴

其中像啼,各個(gè)模塊間的關(guān)系如下所示


模塊間關(guān)系

下面,我們來(lái)進(jìn)行模塊的創(chuàng)建潭苞,以Core模塊為例:

  • 選擇new -> project -> iOS -> Framework忽冻,新建一個(gè)模塊

    創(chuàng)建library

  • 選擇正確的GroupWorkSpace(這里需要注意一點(diǎn):創(chuàng)建的library最好放在主工程根目錄下,否則后續(xù)podfile執(zhí)行pod install時(shí)會(huì)報(bào)錯(cuò))

    library與工程關(guān)聯(lián)

  • 將創(chuàng)建的libraryBuild Settings -> Mach-O Type修改為靜態(tài)庫(kù) Static Library

    修改配置

3此疹、主工程調(diào)用library

  • 在CJLCore中新建一個(gè)文件僧诚,并添加如下代碼
//類需要聲明為public
public class CJLCoreSetting: NSObject {
    //屬性需要聲明為public
    public static let SCRET_KEY = "SCRET_KEY"
}
  • Build Phases -> Headers -> Public中將新建的文件添加為public,這樣主工程才能訪問(wèn)該文件

    修改配置2

  • 在主工程中蝗碎,選擇target -> Linked Frameworks Library中添加CJLCore湖笨,只需要build主工程,library能夠自動(dòng)聯(lián)編

    導(dǎo)入

4蹦骑、使用

首先import CJLCore慈省,然后使用

使用

這里需要注意的是,子library之間的互相調(diào)用眠菇,與主工程調(diào)用library類似边败,主需要添加依賴、暴露header即可

5捎废、使用cocoapods管理三方依賴

假設(shè)我們需要在CJLCore中封裝網(wǎng)絡(luò)層代碼笑窜,需要用到三方庫(kù)Alamofire,在podfile中

platform :ios, '9.0'
inhibit_all_warnings!
use_frameworks!

#配置workspace路徑
workspace 'Modularization.xcworkspace'

################# 三方依賴
# 公有
def workspace_pods
  pod 'SwiftyJSON'
end

# 主工程
def project_only_pods
  pod 'SnapKit'
end

#網(wǎng)絡(luò)
def network_layer_pods
  pod 'Alamofire'
end

################# 模塊
target 'CJLCore' do
  #配置libray路徑
  project 'CJLCore/CJLCore.xcodeproj'
  
  workspace_pods
  network_layer_pods

end

################# 主工程
target 'Modularization' do
  
  workspace_pods
  project_only_pods
  network_layer_pods

  target 'ModularizationTests' do
    inherit! :search_paths

  end

  target 'ModularizationUITests' do

  end

end

到此登疗,一個(gè)本地組件化的模塊就配置完成了

cocoapods組件化

除了本地組件化排截,還可以使用cocoapods,其原理如下圖所示

cocoapods組件化流程

這里還是以本地組件化中的結(jié)構(gòu)為例

1谜叹、創(chuàng)建私有倉(cāng)庫(kù)

  • 在github上創(chuàng)建一個(gè)MySpecs倉(cāng)庫(kù)
    具體步驟:登錄github-->點(diǎn)擊右上角“+”-->選擇 new repository-->輸入Repository name為MySpecs匾寝,選擇倉(cāng)庫(kù)類型為 private,點(diǎn)擊Create repository荷腊。

  • 將私有倉(cāng)庫(kù)添加至本地~/.cocoapods/repos目錄

pod repo add mySpecs https://github.com/xxx/MySpecs.git

2艳悔、創(chuàng)建pods 工程,即組件化工程

  • 使用終端創(chuàng)建CJLServices模塊
pod lib create CJLServices
  • 根據(jù)提示依次輸入:ios女仰、swift猜年、yes抡锈、none、no乔外、CJL


    創(chuàng)建-1
  • 進(jìn)入模塊的目錄床三,將文件拷貝至CJLServices -> Classes

    粘貼文件

  • 執(zhí)行pod install,會(huì)將Classes更新至pods中

    執(zhí)行結(jié)果

3、配置pods工程

修改模塊的配置文件杨幼,即CJLServices.podspec

  • 如果需要依賴三方庫(kù)撇簿,需要配置s.dependency
s.dependency 'AFNetworking'
  • 如果模塊間需要相互引用,同樣需要配置s.dependency差购,以CJLBase為例四瘫,需要引用CJLService
//********1、修改 podspec 文件
s.dependency 'CJLServices'

//********2欲逃、修改 podfile 文件
pod 'CJLServices', :path => '../../CJLServices'
  • 如果需要加載資源找蜜,例如圖片、json稳析、bundle文件等
    • 1洗做、在模塊的Assets文件夾 中添加資源文件
    • 2、在specs里配置資源路徑(必須配置U镁印诚纸!否則無(wú)法讀取資源)
    • 3、訪問(wèn)時(shí)需要指定資源文件路徑
//*****1裕菠、修改 podspec 文件
s.resource_bundles = {
     'CJLBase' => ['CJLBase/Assets/*']
   }
   
//*****2咬清、使用
let bundlePath: String = Bundle.init(for: dynamicClass.self).resourcePath! + "/CJLBase.bundle"
let bundle = Bundle(path: bundlePath)
if let path = bundle?.path(forResource: "mouse", ofType: "jpg"){
    self.imgView.image = UIImage(contentsOfFile: path)
}           

同理,模塊中的xib奴潘,json文件的獲取方式也是一樣的

4、提交至git

這里提交至git的模塊是pods工程才可以影钉,以CJLBase為例

  • 需要在github上創(chuàng)建一個(gè)私有repository画髓,命名為CJLBase

  • 執(zhí)行以下終端命令

$git init
$git add .
$ git commit -am "第一次提交" 
//即第一個(gè)步驟中創(chuàng)建的倉(cāng)庫(kù)地址
$ git remote add origin https://github.com/xxx/CJLBase.git
 
$ git push origin master 
//一定要有標(biāo)簽,不然會(huì)有下面的警告
//podspec文件中獲取Git版本控制的項(xiàng)目需要tag號(hào)平委,
$ git tag -m "first release" "0.1.0" 
$ git push --tags 

5奈虾、驗(yàn)證podspec文件

執(zhí)行終端命令 pod spec lint

注意:pod spec相對(duì)于pod lib會(huì)更為精確,

  • pod lib相當(dāng)于只驗(yàn)證一個(gè)本地倉(cāng)庫(kù)廉赔,
  • pod spec會(huì)同時(shí)驗(yàn)證本地倉(cāng)庫(kù)和遠(yuǎn)程倉(cāng)庫(kù)肉微。

6、提交到私有倉(cāng)庫(kù)

執(zhí)行以下命令

pod repo push [本地Spec Repo名稱][podspec文件路徑]
 
//******舉例
$ pod repo push MySpecs CJLBase.podspec

提交成功后蜡塌,可在本地倉(cāng)庫(kù)中看到提交路徑MySpecs -> CJLBase

7碉纳、使用

  • 新建一個(gè)工程,在項(xiàng)目的podfile里添加
#私有spec倉(cāng)庫(kù)的地址馏艾,而不是某個(gè)pod倉(cāng)庫(kù)的地址
source 'https://github.com/xxx/MySpecs'
pod 'CJLBase'
  • 執(zhí)行pod install即可

參考鏈接

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末劳曹,一起剝皮案震驚了整個(gè)濱河市奴愉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌铁孵,老刑警劉巖锭硼,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異蜕劝,居然都是意外死亡檀头,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門岖沛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)鳖擒,“玉大人,你說(shuō)我怎么就攤上這事烫止〗裕” “怎么了?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵馆蠕,是天一觀的道長(zhǎng)期升。 經(jīng)常有香客問(wèn)我,道長(zhǎng)互躬,這世上最難降的妖魔是什么播赁? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮吼渡,結(jié)果婚禮上容为,老公的妹妹穿的比我還像新娘。我一直安慰自己寺酪,他們只是感情好坎背,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著寄雀,像睡著了一般得滤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上盒犹,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天懂更,我揣著相機(jī)與錄音,去河邊找鬼急膀。 笑死沮协,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的卓嫂。 我是一名探鬼主播慷暂,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼命黔!你這毒婦竟也來(lái)了呜呐?” 一聲冷哼從身側(cè)響起就斤,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蘑辑,沒想到半個(gè)月后洋机,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡洋魂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年绷旗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片副砍。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡衔肢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出豁翎,到底是詐尸還是另有隱情角骤,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布心剥,位于F島的核電站邦尊,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏优烧。R本人自食惡果不足惜蝉揍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望畦娄。 院中可真熱鬧又沾,春花似錦、人聲如沸熙卡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)再膳。三九已至挺勿,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間喂柒,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來(lái)泰國(guó)打工禾嫉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留灾杰,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓熙参,卻偏偏與公主長(zhǎng)得像艳吠,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子孽椰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355