修改說(shuō)明:有朋友反映Xcode9編譯RAC4.x失敗,無(wú)法設(shè)置Use Legacy Swift Language Version 的問(wèn)題】既螅現(xiàn)在將RAC版本改成了2.5(OC版本)庆聘。感謝朋友們的反饋铜犬。git clone 之后執(zhí)行pod install即可匣掸。不用再設(shè)置UseLegacySwiftLanguage Version霸琴。
? ? ? 組件化在業(yè)界已經(jīng)炒的水深火熱播聪,關(guān)于組件化的好處和組件化的方案網(wǎng)上已經(jīng)有大篇的文章了朽基。(Casa的這篇文章對(duì)幾種方案的利弊講述的很不錯(cuò))筆者就不在贅述了。筆者通過(guò)拆分一個(gè)現(xiàn)有的demo來(lái)簡(jiǎn)單聊一下項(xiàng)目實(shí)施組件化的過(guò)程(將分為上篇离陶、中篇稼虎、下三篇)。
## 一霎俩、Demo簡(jiǎn)要說(shuō)明
demo可以從github下載(下載之后執(zhí)行pod install ), 因?yàn)橹坝肦AC+MVVM寫(xiě)項(xiàng)目,這里用了RAC4.x沉眶。pod install之后需要修改一下ReactiveCocoa和Result的UseLegacySwiftLanguage Version 為YES打却。按照下面的方式解決即可:
設(shè)置好之后編譯運(yùn)行就ok了。(接口不太穩(wěn)定谎倔,第一次運(yùn)行可能沒(méi)數(shù)據(jù)柳击,再運(yùn)行一次就ok了)
demo采用了“去model化”的設(shè)計(jì),關(guān)于“去model化”的優(yōu)勢(shì)《去model化和數(shù)據(jù)對(duì)象》講述的很清楚片习。
以下內(nèi)容摘自《iOS應(yīng)用架構(gòu)談 網(wǎng)絡(luò)層設(shè)計(jì)方案》
交付什么樣的數(shù)據(jù)給業(yè)務(wù)層捌肴?
我見(jiàn)過(guò)非常多的App的網(wǎng)絡(luò)層在拿到JSON數(shù)據(jù)之后槽地,會(huì)將數(shù)據(jù)轉(zhuǎn)變成對(duì)應(yīng)的對(duì)象原型阻逮。注意牢硅,我這里指的不是NSDictionary萝映,而是類(lèi)似Item這樣的對(duì)象。這種做法是能夠提高后續(xù)操作代碼的可讀性的殴穴。在比較直覺(jué)的思路里面,是需要這部分轉(zhuǎn)化過(guò)程的,但這部分轉(zhuǎn)化過(guò)程的成本是很大的卦碾,主要成本在于:
數(shù)組內(nèi)容的轉(zhuǎn)化成本較高:數(shù)組里面每項(xiàng)都要轉(zhuǎn)化成Item對(duì)象,如果Item對(duì)象中還有類(lèi)似數(shù)組起宽,就很頭疼洲胖。轉(zhuǎn)化之后的數(shù)據(jù)在大部分情況是不能直接被展示的,為了能夠被展示坯沪,還需要第二次轉(zhuǎn)化绿映。只有在API返回的數(shù)據(jù)高度標(biāo)準(zhǔn)化時(shí),這些對(duì)象原型(Item)的可復(fù)用程度才高,否則容易出現(xiàn)類(lèi)型爆炸叉弦,提高維護(hù)成本丐一。
調(diào)試時(shí)通過(guò)對(duì)象原型查看數(shù)據(jù)內(nèi)容不如直接通過(guò)NSDictionary/NSArray直觀(guān)。
同一API的數(shù)據(jù)被不同View展示時(shí)淹冰,難以控制數(shù)據(jù)轉(zhuǎn)化的代碼库车,它們有可能會(huì)散落在任何需要的地方。
其實(shí)我們的理想情況是希望API的數(shù)據(jù)下發(fā)之后就能夠直接被View所展示樱拴。首先要說(shuō)的是柠衍,這種情況非常少。另外晶乔,這種做法使得View和API聯(lián)系緊密珍坊,也是我們不希望發(fā)生的。
在設(shè)計(jì)安居客的網(wǎng)絡(luò)層數(shù)據(jù)交付這部分時(shí)正罢,我添加了reformer(名字而已阵漏,叫什么都好)這個(gè)對(duì)象用于封裝數(shù)據(jù)轉(zhuǎn)化的邏輯,這個(gè)對(duì)象是一個(gè)獨(dú)立對(duì)象腺怯,事實(shí)上袱饭,它是作為Adaptor模式存在的。我們可以這么理解:想象一下我們洗澡時(shí)候使用的蓮蓬頭呛占,水管里出來(lái)的水是API下發(fā)的原始數(shù)據(jù)虑乖。reformer就是蓮蓬頭上的不同水流擋板,需要什么模式晾虑,就撥到什么模式疹味。
以下內(nèi)容摘自《iOS應(yīng)用架構(gòu)談 組件化方案》
組件化方案中的去model設(shè)計(jì)
組件間調(diào)用時(shí),是需要針對(duì)參數(shù)做去model化的帜篇。如果組件間調(diào)用不對(duì)參數(shù)做去model化的設(shè)計(jì)糙捺,就會(huì)導(dǎo)致業(yè)務(wù)形式上被組件化了,實(shí)質(zhì)上依然沒(méi)有被獨(dú)立笙隙。
假設(shè)模塊A和模塊B之間采用model化的方案去調(diào)用洪灯,那么調(diào)用方法時(shí)傳遞的參數(shù)就會(huì)是一個(gè)對(duì)象。
如果對(duì)象不是一個(gè)面向接口的通用對(duì)象竟痰,那么mediator的參數(shù)處理就會(huì)非常復(fù)雜签钩,因?yàn)橐獏^(qū)分不同的對(duì)象類(lèi)型。如果mediator不處理參數(shù)坏快,直接將對(duì)象以范型的方式轉(zhuǎn)交給模塊B铅檩,那么模塊B必然要包含對(duì)象類(lèi)型的聲明。假設(shè)對(duì)象聲明放在模塊A莽鸿,那么B和A之間的組件化只是個(gè)形式主義昧旨。如果對(duì)象類(lèi)型聲明放在mediator拾给,那么對(duì)于B而言,就不得不依賴(lài)mediator兔沃。但是蒋得,大家可以從上面的架構(gòu)圖中看到,對(duì)于響應(yīng)請(qǐng)求的模塊而言粘拾,依賴(lài)mediator并不是必要條件窄锅,因此這種依賴(lài)是完全不需要的,這種依賴(lài)的存在對(duì)于架構(gòu)整體而言缰雇,是一種污染入偷。
如果參數(shù)是一個(gè)面向接口的對(duì)象,那么mediator對(duì)于這種參數(shù)的處理其實(shí)就沒(méi)必要了械哟,更多的是直接轉(zhuǎn)給響應(yīng)方的模塊疏之。而且接口的定義就不可能放在發(fā)起方的模塊中了,只能放在mediator中暇咆。響應(yīng)方如果要完成響應(yīng)锋爪,就也必須要依賴(lài)mediator,然而前面我已經(jīng)說(shuō)過(guò)爸业,響應(yīng)方對(duì)于mediator的依賴(lài)是不必要的其骄,因此參數(shù)其實(shí)也并不適合以面向接口的對(duì)象的方式去傳遞。
因此扯旷,使用對(duì)象化的參數(shù)無(wú)論是否面向接口拯爽,帶來(lái)的結(jié)果就是業(yè)務(wù)模塊形式上是被組件化了,但實(shí)質(zhì)上依然沒(méi)有被獨(dú)立钧忽。
在這種跨模塊場(chǎng)景中毯炮,參數(shù)最好還是以“去model化”的方式去傳遞,在iOS的開(kāi)發(fā)中耸黑,就是以字典的方式去傳遞桃煎。這樣就能夠做到只有調(diào)用方依賴(lài)mediator,而響應(yīng)方不需要依賴(lài)mediator大刊。然而在去model化的實(shí)踐中为迈,由于這種方式自由度太大,我們至少需要保證調(diào)用方生成的參數(shù)能夠被響應(yīng)方理解缺菌,然而在組件化場(chǎng)景中曲尸,限制去model化方案的自由度的手段,相比于網(wǎng)絡(luò)層和持久層更加容易得多男翰。
因?yàn)榻M件化天然具備了限制手段:參數(shù)不對(duì)就無(wú)法調(diào)用!無(wú)法調(diào)用時(shí)直接debug就能很快找到原因纽乱。
本文中demo的大致結(jié)構(gòu)如下:
將一個(gè)項(xiàng)目組件化拆分掉蛾绎,一般會(huì)拆分一些基礎(chǔ)組件、一些功能組件和業(yè)務(wù)組件。將拆分好的組件放到遠(yuǎn)程倉(cāng)庫(kù)租冠,統(tǒng)一通過(guò)Cocoapods進(jìn)行管理鹏倘。
## 二、 幾個(gè)基本概念
當(dāng)然顽爹,要實(shí)現(xiàn)這個(gè)管理的過(guò)程纤泵,有一些概念還是必須知道的。
如上圖所示: 遠(yuǎn)程索引庫(kù)镜粤、本地索引庫(kù)捏题、遠(yuǎn)程代碼庫(kù)、本地代碼庫(kù)肉渴。筆者通過(guò)拆分demo 中的一個(gè)category的基礎(chǔ)組件說(shuō)明上面的四個(gè)概念公荧。
## 三、實(shí)踐
第一步:基礎(chǔ)組件Category
一同规、遠(yuǎn)程索引庫(kù)
什么是遠(yuǎn)程索引庫(kù)循狰?
? ? ? ? 每創(chuàng)建一個(gè)組件都會(huì)帶有一個(gè) xxx.podspec 的索引文件。專(zhuān)門(mén)用來(lái)存放這些索引文件的庫(kù)就叫做索引庫(kù)券勺。我們需要將這些索引文件上傳到遠(yuǎn)程索引庫(kù)才能保證其他的同事能夠拿來(lái)用绪钥。
創(chuàng)建遠(yuǎn)程索引庫(kù)( 注:這里是在github上創(chuàng)建了一個(gè)public的organization名字叫FFComponent)筆者這里創(chuàng)建的public的,自己公司的項(xiàng)目創(chuàng)建private的私有索引庫(kù)即可关炼,私有索引的步驟和pubic的操作方式一樣
遠(yuǎn)程索引庫(kù)已經(jīng)創(chuàng)建成功程腹,可以看到遠(yuǎn)程索引庫(kù)的地址
二、 本地索引庫(kù) (本地索引庫(kù)就是用來(lái)存放本地索引文件的庫(kù))
1. 打開(kāi)終端 pod repo 查看一下當(dāng)前有哪些本地索引庫(kù)(如果你之前沒(méi)有創(chuàng)建過(guò)盗扒,應(yīng)該只有一個(gè)master)
2. 通過(guò)pod repo add <本地索引庫(kù)的名字>? <遠(yuǎn)程索引庫(kù)的地址> 跪楞,創(chuàng)建本地索引庫(kù)并和遠(yuǎn)程索引庫(kù)做關(guān)聯(lián)(注:本地索引庫(kù)的名字建議和遠(yuǎn)程索引庫(kù)起的名字一樣)
3. 通過(guò)下面的方式可以查看本地索引庫(kù)的物理地址
三、遠(yuǎn)程代碼庫(kù) (代碼實(shí)際存放的遠(yuǎn)程倉(cāng)庫(kù))
創(chuàng)建遠(yuǎn)程代碼倉(cāng)庫(kù)(和創(chuàng)建遠(yuǎn)程索引庫(kù)的方式一樣)侣灶,創(chuàng)建一個(gè)FFCategoryKit的遠(yuǎn)程代碼庫(kù)甸祭,用來(lái)存放FFCategory組件的代碼。同樣獲取到FFCategoryKit組件的遠(yuǎn)程代碼庫(kù)地址褥影。
四池户、本地代碼庫(kù)
創(chuàng)建FFCategoryKit組件本地代碼庫(kù)
1. pod lib create <組件名>? 創(chuàng)建本地代碼組件模版庫(kù)(根據(jù)自身需求對(duì)下面的提示信息做選擇就好)
2. 編譯swift版本錯(cuò)誤解決,修改一下ReactiveCocoa和Result的UseLegacySwiftLanguage Version 為YES凡怎。
3 .編譯運(yùn)行通過(guò)看下效果校焦。接著把FlowerField_Component 里的Others路徑下的文件夾拖入到組件FFCategoryKit的classes路徑下。
4. 接著cd到Example下進(jìn)行pod install (把剛才拖入到classes里的文件夾pod進(jìn)來(lái))
5. 編譯組件看是否報(bào)錯(cuò)统倒,編譯通過(guò)后需要修改podspecs索引文件寨典,一般需要修改下面幾個(gè)問(wèn)題。
a. 修改版本號(hào)
b. 修改項(xiàng)目的簡(jiǎn)單概述和詳細(xì)描述
c. 修改homepage和source地址
d. 添加依賴(lài)庫(kù)
修改前的狀態(tài)如下圖所示:
修改對(duì)應(yīng)的地方即可
修改后如下:
6. 編譯運(yùn)行通過(guò)后房匆,提交組件到遠(yuǎn)程代碼庫(kù)并打tag.
-? git add .
- git commit -m “xxx"
- git remote add origin 遠(yuǎn)程代碼倉(cāng)庫(kù)地址
- git push origin master
- git tag 版本號(hào) (注:這里的版本號(hào)必須和podspec里寫(xiě)的版本號(hào)一致)
- git push --tags
7.? 接下來(lái)可以驗(yàn)證podspec索引文件是否正確
首先耸成,通過(guò)pod lib lint FFCategoryKit.podspec --verbose --allow-warnings 驗(yàn)證本地索引文件是否正確
也可以略過(guò)本地驗(yàn)證
直接通過(guò)pod spec lint --verbose --allow-warnings 命令驗(yàn)證podspec索引文件(既驗(yàn)證本地同時(shí)驗(yàn)證遠(yuǎn)程的podspec)
這個(gè)命令是驗(yàn)證遠(yuǎn)程podspec是否正確报亩,就是驗(yàn)證提交到代碼倉(cāng)庫(kù)里的podspec是否正確
--verbose 是為了打印更加詳細(xì)的信息方便查看
有時(shí)會(huì)遇到這樣的錯(cuò)誤
驗(yàn)證時(shí)發(fā)現(xiàn)`source_files`匹配不到文件
此時(shí),去遠(yuǎn)程代碼庫(kù)看看對(duì)應(yīng)的Classes是否為空
錯(cuò)誤說(shuō)明:如果遇到下面的錯(cuò)誤井氢,就按照提示在終端輸入`echo "2.3" > .swift-version`弦追,然后在繼續(xù)驗(yàn)證,驗(yàn)證通過(guò)后再通過(guò) pod repo push 提交到遠(yuǎn)程索引倉(cāng)庫(kù)花竞,如果沒(méi)有遇到該問(wèn)題自動(dòng)略過(guò).
8. 驗(yàn)證通過(guò)后劲件,pod repo push <本地索引庫(kù)> <索引文件名> - -verbose - -allow-warnings 提交索引文件到遠(yuǎn)程索引庫(kù)。
本地也可以查看已成功
9. 接下來(lái)回到FlowerField_Component工程修改podfile文件,把FFCategoryKit組件pod進(jìn)來(lái)(注:需要在Podfile中指定組件遠(yuǎn)程索引庫(kù)地址约急,如果不指定默認(rèn)會(huì)從master的索引庫(kù)查找就會(huì)報(bào)找不到組件)
Podfile文件修改如下 :
執(zhí)行pod install零远,按照上面同樣的方式修改一下ReactiveCocoa和Result的UseLegacySwiftLanguage Version 成YES
同樣在項(xiàng)目查看已經(jīng)pod進(jìn)來(lái)了。
10. 編譯運(yùn)行如下
第二步:基礎(chǔ)組件APIs
? ? ? ? 對(duì)項(xiàng)目FlowerField_Component中Others下的APIs實(shí)施組件化烤宙,因?yàn)锳PIs組件中會(huì)依賴(lài)AFN框架遍烦,所以這里會(huì)說(shuō)明一下。按照和FFCategoryKit組件同樣的方式來(lái)創(chuàng)建APIs組件對(duì)應(yīng)的遠(yuǎn)程代碼庫(kù)躺枕,本地代碼模版庫(kù)服猪,索引庫(kù)就不用創(chuàng)建了。
1. FFAPIs組件遠(yuǎn)程代碼庫(kù)和本地代碼模版庫(kù)
2. 同樣將APIs文件夾拖入到FFAPIsKit下的classes下面拐云。因?yàn)锳PIs中的NetworkHelper類(lèi)依賴(lài)AFN框架罢猪,所以需要修改podspec索引文件,修改如下:
3. 回到Example進(jìn)行pod install, 編譯運(yùn)行通過(guò)后進(jìn)行提交組件到遠(yuǎn)程代碼庫(kù)叉瘩。按照同樣的方式打好tag膳帕,驗(yàn)證podspec并提交索引文件。然后在本地索引庫(kù)查看發(fā)現(xiàn)FFAPIsKit組件已經(jīng)完成了薇缅。
4. 最后危彩,同樣回到FlowerField_Component修改Podfile后pod install。修改ReactiveCocoa和Result的UseLegacySwiftLanguage Version 為YES后編譯運(yùn)行泳桦。
5. 采用同樣的方式對(duì)configs汤徽、reformerKeys、tools灸撰、mainView進(jìn)行組件化谒府,創(chuàng)建組件FFConfigsKit、FFReformerKeysKit浮毯、FFToolsKit完疫、FFMainViewKit。
說(shuō)明:FFToolsKit 依賴(lài)MBProgressHUD庫(kù)债蓝; 別忘記在對(duì)應(yīng)的podspec索引文件中添加依賴(lài)庫(kù)壳鹤。
6. 基礎(chǔ)組件化結(jié)束之后,F(xiàn)lowerField_Component中Podfile如下:
首先感謝您能堅(jiān)持聽(tīng)我啰嗦到這里饰迹。到這里上篇就結(jié)束了器虾。后兩篇將陸續(xù)更新出來(lái)讯嫂。項(xiàng)目組件化過(guò)程中一定也會(huì)遇到各樣的問(wèn)題。歡迎大家留言交流互相學(xué)習(xí)兆沙。我的郵箱 jiajung@aliyun.com? 也歡迎大家Emial交流。