三層模式
一般的iOS教程,都是MVC,從界面到數(shù)據(jù),一次搞定。從網(wǎng)絡(luò)讀取數(shù)據(jù),然后根據(jù)實際情況,將數(shù)據(jù)處理一下,就在界面上顯示。M是指數(shù)據(jù),一般都是類型定義;VC一般都在controller中實現(xiàn),特別是代碼寫界面的實現(xiàn)。這樣就導致controller任務(wù)很重,幾乎做了所有的事情。所以,iOS一般不需要架構(gòu),因為controller幾乎可以一步到位,而MVC的概念又足夠簡單,無需再分層,只要考慮如果分模塊,分任務(wù)就可以了。這就是現(xiàn)狀。
iOS中的MVC看起來是三層,但是在現(xiàn)實中就是一層,一步到位。在現(xiàn)狀的基礎(chǔ)上往前走一小步,就是我們現(xiàn)狀考慮的iOS架構(gòu)。目的有兩個, 一個是分三層,讓理念和現(xiàn)實更接近,就分三層先固化下來。另一個是降低controller的復雜度,將界面,邏輯,數(shù)據(jù)處理的內(nèi)容都分離出去,只保留調(diào)度者的作用。在分層中,將view和controller都分到界面層,因為view不能離開controller單獨存在。在這里controller就相當于一個大總管,不做具體的事,一方面讓view有展示的機會,另一方面,讓邏輯層函數(shù)有表現(xiàn)的機會。
iOS開發(fā)繞不過的兩個交互界面,一是產(chǎn)品和設(shè)計,特點是多變,而且變的成本很低;二是后臺MTP,特點是基本上不愿意變,變得也很慢。等這兩者都差不多了,才輪到iOS開發(fā)自己,那個時候就發(fā)現(xiàn)壓力全來了,前面等,浪費很多時間,現(xiàn)在加班也來不及。為了解決這種被動局面,可以考慮把當前MVC一步到位的模式分為界面,邏輯,數(shù)據(jù)三部分。界面跟設(shè)計對接,數(shù)據(jù)跟后臺MTP對接,這兩層都盡量薄,不需要太多考慮復用的問題,膠水代碼或者盡量不用代碼,關(guān)鍵是應(yīng)對要快,改起來方便。邏輯層,盡量大,盡量能復用,模塊可以分得多,分得細,降低耦合度,并且隨著業(yè)務(wù)發(fā)展,可以沉淀出很多自己獨特的內(nèi)容。
界面
界面開發(fā)一直有IB和代碼的爭論。對于IB,合作開發(fā),影響性能是一直被詬病的兩點。就像當年的ARC和MRC的爭論一樣,雙方都有道理,也不需要有對錯,完全是選擇而已。所以,我們的選擇很簡單,遵循蘋果推薦的方式,采用IB,并且用storyboard,sizeclass,imageset等最新的概念。合作開發(fā),代碼管理,影響性能之類的都是偽命題,都不是我們所關(guān)注的重點。
界面開發(fā)的第二個重點是把顯示邏輯抽出來,交給view model;將業(yè)務(wù)邏輯抽出來,交給獨立的logic模塊;將數(shù)據(jù)部分抽出來,交給各個data source;controller中只保留不得不保留的部分,最輕量級化。controller很難復用,所以能有多簡單就做得多簡單,不準留一點非他不可的東西。
界面開發(fā)的第三個問題是view的復用。這塊的主流和習慣也是代碼寫組件,這沒什么不好,也是一個價值觀的問題。提高代碼質(zhì)量的最好辦法就是沒有代碼,所以很大一部分的組件可以用xib直接實現(xiàn),用起來也方便。至于動畫和動態(tài)界面部分,目前只能用代碼來實現(xiàn),就用代碼來做。
這一層的比重,最好不要超過25%,并且代碼越少越好。邏輯
iOS程序崩潰有80%出現(xiàn)在是否為空,即nil上面。界面元素,一般都是非空的,不顯示,可以用view的hiden屬性來表示,也可以用字符串的“”來表示。一旦碰到空,也就是nil,就有崩潰的危險。但是網(wǎng)絡(luò)來的數(shù)據(jù),一般都是可能為nil的。就算業(yè)務(wù)規(guī)定某個字段不能為空,比如uerID,但是實際中,網(wǎng)絡(luò)都不通,對客戶端來說,就是nil。如果程序開發(fā)時不考慮這一點,那么就有可能開發(fā)時什么都正常,但是實際中就是不斷有崩潰。從這個角度來說,將邏輯層單獨列出來,專門處理“數(shù)據(jù)層所有字段都可能為空;業(yè)務(wù)邏輯上,有些字段可能為空,有些字段不允許為空;界面上,所有字段都不能為空”這種情況,也是非常有意義的。
頁面和頁面跳轉(zhuǎn),交互可能變化比較多,但是在業(yè)務(wù)邏輯上,可能改動很少或者基本可固定。另外,界面的分類標準和業(yè)務(wù)邏輯上的分類標準很可能不一致。比如有些復雜頁面,涉及到的邏輯層面很多,但是也有好多頁面,都屬于一個業(yè)務(wù)邏輯概念。從這個角度講,將邏輯層單獨出來,按照業(yè)務(wù)標準分模塊,盡量考慮復用,也是很有價值的。
這一層的比重,最好能夠超過50%數(shù)據(jù)
數(shù)據(jù)層的考慮問題方式天生跟邏輯層不一樣。比如,對iOS程序來說,網(wǎng)絡(luò)API是肯定逃不掉的。首先考慮的問題是自己寫還是用第三方庫;用http還是用tcp長連接等等。所以,數(shù)據(jù)層是按數(shù)據(jù)方式作為第一維度考慮的。此外,還有數(shù)據(jù)庫,也就是本地緩存,稍微大一點的app都是繞不過的話題。所以數(shù)據(jù)層的第一步是按照數(shù)據(jù)來源和存儲,操縱方式分模塊。
第二層次,才是按照功能分模塊。這里的建議是數(shù)據(jù)層盡量把重點放在數(shù)據(jù)操縱上面,邏輯方面的內(nèi)容少涉及。就把數(shù)據(jù)層當個二傳手吧,能把數(shù)據(jù)傳輸和存儲搞好就可以了。至于數(shù)據(jù)的邏輯意義,交給邏輯層處理。
這一層的比重,最好不要超過25%
從MVC過渡到MVVM
- 借鑒MVVM的思想,但是不完全遵循MVVM規(guī)范,比如雙向綁定就太復雜
- 不引入ReactiveCocoa,因為增加了復雜度和學習成本
- 界面層可以包含storyboard,xib,view,controller,view model;盡量薄,盡量少用代碼,和UX人員協(xié)作開發(fā);只包含顯示邏輯,不包含業(yè)務(wù)邏輯
- 數(shù)據(jù)層盡量薄,只做“傳聲筒”,將json字段簡單地轉(zhuǎn)換為自定義數(shù)據(jù)類型。只負責把數(shù)據(jù)從服務(wù)端拿到本地,不負責解釋數(shù)據(jù)的意義;和后臺人員一起根據(jù)API接口來實現(xiàn)。
- 調(diào)用接口由界面、數(shù)據(jù)兩層定義,邏輯層負責將這兩層的接口打通,形成落地的閉環(huán)。其他不能放在界面、數(shù)據(jù)兩層的內(nèi)容都放在這一層統(tǒng)一規(guī)劃。
從Cocoa Pods過渡到 Carthage
- 拋棄.a .bundle 方式,統(tǒng)一采用framework方式
- 只使用編譯好的framework模塊,不需要重新編譯
ViewController瘦身
- 不準作為delegate
- 不準有自定義的base controller,不準有自定義繼承
- 不準作為data source
- 不準復用
- 不準作為函數(shù)參數(shù)傳遞
文件命名
- 主動采用workspace模式,并且workspace的名字和project的名字可以不一樣
- 不準有public、common、base等語義不明確的文件夾
- 界面層按頁面跳轉(zhuǎn)分模塊,邏輯層按業(yè)務(wù)邏輯分模塊,數(shù)據(jù)層按數(shù)據(jù)來源或數(shù)據(jù)存儲方式分模塊