項(xiàng)目背景:
在移動(dòng)互聯(lián)網(wǎng)行業(yè)眷茁,公司算得上是一個(gè)元老了睛蛛,趕上了第一波移動(dòng)互聯(lián)網(wǎng)創(chuàng)業(yè)的熱潮,于是公司的APP項(xiàng)目也在那個(gè)時(shí)候應(yīng)運(yùn)而生雏婶,但是任何事物都有兩面性,有時(shí)候早也并不是好事白指,僅僅對于我們iOS的工程來說就是這樣留晚。聽前輩們講,我們APP大概經(jīng)歷了四代人開發(fā)告嘲,大概劃分一下如下:
- 第一代:在那時(shí)候错维,會(huì)寫一個(gè)網(wǎng)絡(luò)請求,會(huì)一個(gè)tableview橄唬,你就可以在這個(gè)領(lǐng)域站得住腳赋焕,所以第一版本沒有任何設(shè)計(jì)而言,只是需要實(shí)現(xiàn)功能
- 第二代:在iOS項(xiàng)目開發(fā)中轧坎,MVC是蘋果力推的架構(gòu)模式宏邮。經(jīng)過了一定時(shí)間積累和沉淀,公司項(xiàng)目逐漸往這個(gè)方向發(fā)展,漸漸有了一些清晰的結(jié)構(gòu)
- 第三代:隨著公司的發(fā)展蜜氨,業(yè)務(wù)的擴(kuò)大械筛,APP的功能越來越多,越來越復(fù)雜飒炎。這時(shí)候APP整個(gè)項(xiàng)目結(jié)構(gòu)開始變得臃腫混亂埋哟,但不敢輕易重構(gòu)
- 第四代:我們現(xiàn)在這一波人,在重構(gòu)的道路上郎汪,全力填前人留下的坑
APP架構(gòu)大概演進(jìn)路線:
MRC → ARC赤赊,MVC → 分層設(shè)計(jì), MVVM煞赢,組件化
我進(jìn)公司的時(shí)候抛计,現(xiàn)在的team leader正在對整個(gè)APP進(jìn)行重構(gòu),據(jù)他說整個(gè)APP已經(jīng)沒法繼續(xù)開發(fā)下去了照筑,結(jié)構(gòu)混亂不堪吹截。由于前面工程使用的MRC,而且當(dāng)時(shí)工程師的開發(fā)水平參差不齊凝危,造成項(xiàng)目線上崩潰率很高波俄。team leader帶著一批人,首先把整個(gè)項(xiàng)目轉(zhuǎn)變成ARC蛾默,換掉一些老的框架懦铺,自己重寫。然后項(xiàng)目被劃分為邏輯底層支鸡,業(yè)務(wù)層冬念,UI層。UI層調(diào)用業(yè)務(wù)層苍匆,業(yè)務(wù)層調(diào)用邏輯層刘急,不允許三層之間相互調(diào)用,這樣一個(gè)整個(gè)軟件架構(gòu)已經(jīng)解決了大部分的耦合了浸踩,對于后面進(jìn)來的同事可以很快了解熟悉APP叔汁,對于后續(xù)持續(xù)化開發(fā)有了質(zhì)的提升
目前APP結(jié)構(gòu):
邏輯層:HTTP框架,TCP框架检碗,數(shù)據(jù)庫框架等(穩(wěn)定据块,不會(huì)隨APP業(yè)務(wù)變化的內(nèi)容)
業(yè)務(wù)層:適應(yīng)公司自有業(yè)務(wù),如會(huì)員折剃,資料另假,分享等的管理(適應(yīng)公司業(yè)務(wù),隨時(shí)增加或者修改)
UI層:這里說UI層是簡稱怕犁,說的就是APP開發(fā)的一層边篮,下面也具體談?wù)勥@一層己莺,到了這一層我們才會(huì)談到MVC,MVVM或者是其他的一些架構(gòu)戈轿。我們APP之前在這一層使用的是傳統(tǒng)MVC開發(fā)凌受,對大多數(shù)人來說,MVC非常熟悉親切思杯,這也是Apple對于iOS開發(fā)推薦的架構(gòu)模式
MVC與MVVM:
MVC
我們所熟知的MVC其實(shí)Apple給我們提供的Cocoa MVC胜蛉,Apple提倡的MVC中,view和model是相互獨(dú)立的色乾,只通過controller來進(jìn)行交互
- Model進(jìn)行數(shù)據(jù)管理
- View根據(jù)數(shù)據(jù)進(jìn)行視圖渲染
- Controller對Model以及View進(jìn)行調(diào)配
但是這里存在一個(gè)問題誊册,由于controller中本身存在一個(gè)view,所以很難做到view和controller完全獨(dú)立暖璧,因此controller要管理view的生命周期和響應(yīng)一些界面操作雖然model可以分擔(dān)一些簡單數(shù)據(jù)處理案怯,但是最終還是會(huì)發(fā)現(xiàn)controller變成了所有東西的代理和數(shù)據(jù)源。一旦業(yè)務(wù)相對復(fù)雜一點(diǎn)澎办,controller代碼量會(huì)非常大殴泰,而且隨著業(yè)務(wù)的增加,代碼量會(huì)持續(xù)增加浮驳,而model和view卻相對穩(wěn)定,這對于以后的維護(hù)是災(zāi)難性的捞魁。(我們的APP中當(dāng)時(shí)存在數(shù)個(gè)代碼5000行以上的控制器至会,重構(gòu)時(shí)的痛苦自不必多說)
有一點(diǎn)值得思考,我們都應(yīng)該遇到過這樣的場景谱俭,tableview里給cell填充數(shù)據(jù)的時(shí)候調(diào)用的方法大概是這樣
- (Void)setData:(XXXModel)model
這里大家有沒有注意到奉件,cell里面是有model的,所以這里是不是已經(jīng)違背了MVC的原則了呢累颂,但是這種情況確實(shí)是一直在我們開發(fā)的過程中發(fā)生及塘,我們也沒感覺到哪里奇怪匀油。如果嚴(yán)格遵守MVC的話,你會(huì)把對cell的設(shè)置放在controller中煤痕,不向view傳遞一個(gè)model對象,如果cell的樣式過多接谨,這樣controller的體積是不可想象的摆碉。所以其實(shí)我們在開發(fā)過程中已經(jīng)不知不覺的在修改MVC這種架構(gòu)了,因?yàn)樗_實(shí)是存在弊端的脓豪。
總結(jié)一下MVC:
- 優(yōu)點(diǎn):在項(xiàng)目初期巷帝,MVC的確可以快速的構(gòu)建一個(gè)APP,并且結(jié)構(gòu)清晰扫夜,對于程序員來說更容易理解楞泼,上手開發(fā)很快驰徊,閱讀起來容易
- 缺點(diǎn):隨著公司的業(yè)務(wù)增加,APP更為健壯的時(shí)候堕阔,MVC就顯得不堪重負(fù)棍厂,維護(hù)成本顯著增加,對業(yè)務(wù)的增刪改簡直是災(zāi)難印蔬,一個(gè)動(dòng)作會(huì)牽一發(fā)而動(dòng)全身
如何才是一個(gè)正確姿勢的MVC呢勋桶,我理解的如下:
- model:給controller提供數(shù)據(jù)相關(guān)的接口,可以提供輕量級的業(yè)務(wù)接口
- controller:管理view的什么周期侥猬,監(jiān)聽界面操作例驹,調(diào)度model和view
- view:只用來刷新界面,如展示動(dòng)畫退唠,展示界面元素等
MVVM
MVVM從前兩三年開始在iOS開發(fā)中討論度非常高鹃锈,現(xiàn)在已經(jīng)是一種非常成熟的思想了。其初衷也是為了controller減負(fù)瞧预,把數(shù)據(jù)業(yè)務(wù)處理的部分從controller中移出去
- model:和MVC一樣屎债,基本的數(shù)據(jù)單元
- view:也和MVC差不多,不接受邏輯垢油,只做視圖展示
- viewmodel:處理數(shù)據(jù)盆驹,業(yè)務(wù)邏輯
這里有幾個(gè)重要的地方:
- 首先可以看到controller哪里去了,其實(shí)這里view和controller可以劃歸為一層滩愁,controller只是接收view的事件躯喇,也就是用戶操作界面,然后將事件傳遞給viewmodel處理硝枉。controller在這里扮演的只是一個(gè)中間人的角色
- viewmodel不要包含任何view相關(guān)的東西廉丽,viewmodel之間可以有相互依賴,但是要盡量避免妻味,否則重蹈controller的覆轍正压,變得難以維護(hù)
很多人提到MVVM就提到了Reactive,實(shí)際上兩者完全沒有任何聯(lián)系责球,MVVM是一種軟件架構(gòu)焦履,而Reactive是一種編程思想,我們所說的ReactiveCocoa或者RxSwift是用這種思想編寫的一個(gè)框架棕诵,目的在于讓我們更容易實(shí)現(xiàn)這種編程模式裁良。也就是說不用這兩個(gè)框架,一樣可以實(shí)現(xiàn)MVVM校套。那么到底如何實(shí)現(xiàn)一個(gè)MVVM呢价脾,其實(shí)很簡單:
只要在MVC的基礎(chǔ)上,把Controller拆出一個(gè)ViewModel專門負(fù)責(zé)數(shù)據(jù)處理的事情笛匙,就是MVVM
拆出來的ViewModel怎么和外部通訊呢侨把,這時(shí)候就回到了我們說的Reactive犀变,iOS中我們使用KVO,Notification秋柄,block获枝,delegate和target-action都可以用來做ViewModel和外部的通訊,但是這些都不如Reactive來得優(yōu)雅骇笔,幾種方法具體比較大家可以用簡單代碼實(shí)現(xiàn)一下省店,就會(huì)知道Reactive和MVVM是天生一對了,這也是為什么提到MVVM就會(huì)提到Reactive了笨触。
總結(jié)
還有其他諸如MVCS懦傍,MVP,VIPER等架構(gòu)芦劣,有的只是看過一些介紹粗俱,有的自己稍微嘗試過。得出一個(gè)自己的感受
這些架構(gòu)都是衍生自MVC虚吟,把MVC中某個(gè)部分拆開寸认,得到一個(gè)新的部分,并制定一個(gè)規(guī)范串慰,然后就形成了新的架構(gòu)模式
一個(gè)APP在設(shè)計(jì)架構(gòu)的時(shí)候不能拘泥于這些偏塞,這些只是你掌握的基礎(chǔ)知識(shí)“铞辏看過一句話烛愧,天下架構(gòu)出自MVC。仔細(xì)想想其實(shí)有一定道理掂碱,因?yàn)樗械哪J娇梢猿橄蟪?數(shù)據(jù)管理者
,數(shù)據(jù)加工者
慎冤,數(shù)據(jù)展示者
疼燥。MVC其實(shí)已經(jīng)站在了一個(gè)很高的角度看問題,所以其實(shí)重點(diǎn)是你應(yīng)該怎么拆蚁堤,這里我們APP的原則是這樣的:
- 能從controller里拆出去的盡量拆出去醉者,只保留最核心的部分
- 拆出去的東西能保證有復(fù)用性
- 盡可能的站在更高角度拆分(也就是拆分的粒度盡量大一些,不要拆分成一個(gè)個(gè)很小功能披诗,不然你工程文件的數(shù)量會(huì)太大)
這些說的都是相對的東西撬即,不是絕對的。比如呈队,我們APP有一個(gè)很簡單的頁面好友列表剥槐,只展示一個(gè)頭像,昵稱宪摧,和關(guān)注關(guān)系粒竖,這里有必要去MVVM嗎颅崩,有必要?jiǎng)冸xtableview的各種delegate嗎,一個(gè)簡單的MVC可以說十多分鐘就可以寫完蕊苗,完全沒必要去用那些技巧沿后。
一個(gè)APP的架構(gòu)設(shè)計(jì)應(yīng)該參考自己公司的業(yè)務(wù),因?yàn)槟阕龀龅臇|西是要為公司業(yè)務(wù)服務(wù)的朽砰,脫離了業(yè)務(wù)去談架構(gòu)是空談尖滚。不結(jié)合實(shí)際情況,拿著一堆理論直接上是很容易出問題的瞧柔,我們應(yīng)該在掌握了這些思想的前提下漆弄,結(jié)合自身公司的業(yè)務(wù),靈活使用才是正道胺翘辍置逻!