iOS之MV(X) 架構(gòu)理解分析

前言

相信很多iOS開發(fā)者從學(xué)習(xí)iOS開始就是用的MVC架構(gòu),因為Apple推薦使用MVC,原因:上手快,且開發(fā)效率高。但是在開發(fā)過程中求速度,并沒有嚴格的遵守MVC原則,隨著APP的不斷更新迭代,導(dǎo)致了Controller變成了集Model,View,Controller的一個大集合,代碼維護也變得很難受,網(wǎng)絡(luò)請求,數(shù)據(jù)存儲和處理,業(yè)務(wù)邏輯,用戶交互等基本都是在控制器里面處理,以致幾千行的控制器屢見不鮮,這樣既不好查找bug,也不利于單元測試。所以我去重新認識了一下MVC,也去學(xué)習(xí)了一下MVP以及MVVM。

基本要素

  • ** Models(模型)**:數(shù)據(jù)層,一般用來承載數(shù)據(jù),以及數(shù)據(jù)處理
  • Views (視圖)展示層,將數(shù)據(jù)以UI的形式展示
  • Controller/Persenter/ViewModel(控制器/展示器/視圖模型)業(yè)務(wù)層,它又是Model跟View之間的粘合劑,一般來說,當(dāng)用戶對View操作時它去負責(zé)修改相應(yīng)的Model,當(dāng)Model的值發(fā)生變化時它去負責(zé)更新對應(yīng)的View。

上面提到的數(shù)據(jù)層,展示層,業(yè)務(wù)層,其實就是針對模塊分類而言的三層架構(gòu);而MV(X)這種層次劃分,主要是針對數(shù)據(jù)流動的方向而言的。


MVC

一個標準的MVC它的結(jié)構(gòu)及交互是這樣的



當(dāng)View接收到用戶操作指令時,View移交給Controller處理,Controller去更新Model,Model更新之后通知Controller,控制器再去更新View。我們可以看到:

  • Model它需要提供數(shù)據(jù)給Controller,所以它不僅要負責(zé)拉取數(shù)據(jù)和處理數(shù)據(jù)還要提供數(shù)據(jù)存取的接口,并不只是一個數(shù)據(jù)表達對象,它承擔(dān)的事情會很多,由此可見它是一個胖Model。
  • View的更新是通過暴露的接口或元素交給Controller來執(zhí)行的,而不是直接把Model丟給View;這樣雖然會增加Controller的代碼量,但是也讓View變得很純潔,只需要展示界面元素,以及本身的動畫效果,所以View跟Model是完全分開的,利于View的復(fù)用以及UI的修改。
  • Controller不負責(zé)View的布局及展示邏輯,它只負責(zé)監(jiān)聽 View 層的事件,從Model取數(shù)據(jù)(如果需要),再去更新View。但是由于UIViewController的設(shè)計特殊,它本身自帶一個View,所以導(dǎo)致很多開發(fā)者直接在Controller上進行View布局及展示邏輯,導(dǎo)致了Controller越來越重,很明顯這違背了MVC的思想。我理解的做法是分一個主View出來,在這上面去做View的事情,但是這也多了一層事件的傳遞(這個主View先要接管它上面控件的事件回調(diào),再一一暴露給Controller)。

上面提到了胖Model,其實就是指Model做的事情較多,包含了一些弱業(yè)務(wù),Controller從Model中拿到的數(shù)據(jù),不用做額外的或者非常少的處理,就可以直接應(yīng)用在View上;那么相應(yīng)的就有瘦Model,它僅僅只是表達數(shù)據(jù)的作用。說到這里那么就順便提一下MVCS架構(gòu)模式,它也是MVC的一個變種,從Model中拆出一個Store,專門負責(zé)數(shù)據(jù)拉取和處理,而原來那個胖Model也變成了瘦Model,只是用來承載數(shù)據(jù),這樣Model的維護成本就會變得很低。因為變化也不是很大,就不單獨拿出來說了。

小結(jié)

我覺得在Controller非常臃腫的問題上,MVC不應(yīng)該背這個鍋!,只是開發(fā)者沒有嚴格按照MVC的原則來使用。那么為什么又會衍生出各種架構(gòu)模式,我覺得問題還是在Controller上,因為iOS中Controller叫做UIViewController,盡管我們可以分出一個主View出來做布局及展示邏輯,但是它畢竟自帶一個View且管理著它們的生命周期(viewWillAppear,viewWillDisappear等等),所以C跟V之間的聯(lián)系還是過于緊密。


MVP

還是先看圖吧,畢竟一圖勝千言!



我們發(fā)現(xiàn)MVP跟MVC數(shù)據(jù)流向的方式是一致的,只是流向的對象有點不一樣。那么實質(zhì)上做了什么改變呢?

  • 多出一個Presenter對象,它來扮演View跟Model的協(xié)調(diào)者,取代了MVC中Controller,變成了整個架構(gòu)中的大腦,而且不關(guān)注View/Controller的生命周期,所以它的職責(zé)更加明確。
  • 在上面也說了MVC中V跟C的聯(lián)系過于緊密,那好,在MVP中我們就把Controller跟View統(tǒng)一當(dāng)做View來對待,他們都只負責(zé)UI布局及展示邏輯,并將交互事件傳遞給Persenter處理,所以相比之下模塊劃分更加清晰。
  • View是持有Presenter的,用戶交互事件可以直接傳給Presenter,而View的更新是通過實現(xiàn)事先定義好的協(xié)議,然后由Presenter處理完數(shù)據(jù)再發(fā)起執(zhí)行的,所以View跟Presenter是一對一的關(guān)系。

小結(jié)

MVP跟MVC他們的區(qū)別就是,MVP把Controller當(dāng)做一個View來看待,因為它們本身的聯(lián)系就很緊密,從而避免了Controller的職責(zé)模糊。另外View跟Presenter有一層協(xié)議關(guān)系,所以代碼量相對來說也會增加。


MVVM


我們又發(fā)現(xiàn)MVVM跟MVP很相似:

  • 它們都是將Controller當(dāng)做一個View來處理,上層通過給View分配一個ViewModel/Presenter來做協(xié)調(diào)工作以及業(yè)務(wù)邏輯,很好的避免了視圖展示跟業(yè)務(wù)邏輯的耦合。

不同的是:

  • View跟ViewModel之間做了雙向綁定,ViewModel綁定了View的用戶行為,View綁定了ViewModel的數(shù)據(jù)。什么意思?就是當(dāng)View接收到用戶行為時,ViewModel可以監(jiān)聽到,然后去做相關(guān)邏和數(shù)據(jù)處理;當(dāng)ViewModel的數(shù)據(jù)變化時,View一樣可以監(jiān)聽到,然后自己來刷新數(shù)據(jù)。
  • 這里的View不像MVP的Passive View(被動的View)只能被動的去更新數(shù)據(jù),它是通過監(jiān)聽ViewModel的數(shù)據(jù)變化,然后自己更新數(shù)據(jù)的。這樣從用戶交互->數(shù)據(jù)處理->界面更新就變得自動化。

小結(jié)

ViewModel的職責(zé)之一就是作為一個表現(xiàn)視圖顯示自身所需要的靜態(tài)模型,它有收集,解釋和轉(zhuǎn)換那些數(shù)據(jù)的責(zé)任。另外,綁定可以通過KVO來實現(xiàn),但是有點笨重,可以使用FBKVOController,其實更多的還是通過RAC來做,更能體現(xiàn)MVVM的精髓,也簡化了很多的代碼。


總結(jié)

不管是什么架構(gòu)模式,他們都是圍繞著用戶交互->數(shù)據(jù)處理->界面更新來進行的,只是各自的方式不一樣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容