2017-08-19rickytang0Cocoa開發者社區
MVC
全稱是 Model View Controller,是模型 (model)-視圖 (view)-控制器 (controller) 的縮寫。它表示的是一種常見的客戶端軟件開發框架。
現在,MVC 已經成為主流的客戶端編程框架,在 iOS 開發中,系統為我們實現好了公共的視圖類:UIView,和控制器類:UIViewController。大多數時候,我們都需要繼承這些類來實現我們的程序邏輯,因此,我們幾乎逃避不開 MVC 這種設計模式。
但是,幾十年過去了,我們對于 MVC 這種設計模式真的用得好嗎?其實不是的,MVC 這種分層方式雖然清楚,但是如果使用不當,很可能讓大量代碼都集中在 Controller 之中,讓 MVC 模式變成了 Massive View Controller 模式。
Controller 的臃腫問題何解?
我們來看看 MVC 這種架構的特點。其實設計模式很多時候是為了Don't repeat yourself原則來做的,該原則要求能夠復用的代碼要盡量復用,來保證重用。在 MVC 這種設計模式中,我們發現 View 和 Model 都是符合這種原則的。
對于 View 來說,你如果抽象得好,那么一個 App 的動畫效果可以很方便地移植到別的 App 上,而 Github 上也有很多 UI 控件,這些控件都是在 View 層做了很好的封裝設計,使得它能夠方便地開源給大家復用。
對于 Model 來說,它其實是用來存儲業務的數據的,如果做得好,它也可以方便地復用。比如我當時在做有道云筆記 iPad 版的時候,我們就直接和 iOS 版復用了所有的 Model 層的代碼。在創業做猿題庫客戶端時,iOS 和 iPad 版的 Model 層代碼再次被復用上了。當然,因為和業務本身的數據意義相關,Model 層的復用大多數是在一個產品內部,不太可能像 View 層那樣開源給社區。
說完 View 和 Model 了,那我們想想 Controller,Controller 有多少可以復用的?我們寫完了一個 Controller 之后,可以很方便地復用它嗎?結論是:非常難復用。在某些場景下,我們可能可以用addSubViewController之類的方式復用 Controller,但它的復用場景還是非常非常少的。
如果我們能夠意識到 Controller 里面的代碼不便于復用,我們就能知道什么代碼應該寫在 Controller 里面了,那就是那些不能復用的代碼。在我看來,Controller 里面就只應該存放這些不能復用的代碼,這些代碼包括:
在初始化時,構造相應的 View 和 Model。
監聽 Model 層的事件,將 Model 層的數據傳遞到 View 層。
監聽 View 層的事件,并且將 View 層的事件轉發到 Model 層。
如果 Controller 只有以上的這些代碼,那么它的邏輯將非常簡單,而且也會非常短。
但是,我們卻很難做到這一點,因為還是有很多邏輯我們不知道寫在哪里,于是就都寫到了 Controller 中了,那我們接下來就看看其它邏輯應該寫在哪里。
MVVM
Model-View-ViewModel 的簡寫。但在我的理解可以是Model-ViewModel-Controller-View
為什么要這樣樣理解呢?上面的問題Controller的代碼處理太多東西,導致極其難復用,而且在后期調整業務,更換UI等事情上也會較為困難。
所以我的建議是將Controller的所有業務邏輯都應該移動到ViewModel層上。具體該做些什么呢?
我們可以將網絡請求的借口,及返回的數據寫在ViewModel里面,ViewModel再通知Controller來取得相應的數據,并顯示在view上。
還可以將邏輯計算等方法封裝在ViewModel里面,供Controller調用。當然如果這部分計算復用性很高,你還可以封裝到其他公用的類里面。
而這個ViewModel將會是一個隨時可以被其他功能模塊調用的狀態。而且,一個Controller可以使用一個或多個ViewModel。這樣將會大大提高代碼分復用性,及降低后期的維護。
MVVM 在使用當中,通常還會利用雙向綁定技術,使得 Model 變化時,ViewModel 會自動更新,而 ViewModel 變化時,View 也會自動變化。而這個過程我們可以使用KVO和Notification來實現,但這樣并不是最理想和高效的方式,所以我們需要結合ReactiveCocoa一起使用。
ReactiveCocoa是一個函數式編程(Functional Programming)和響應式編程(React Programming)庫
函數式編程(Functional Programming),函數也變成一等公民了,可以擁有和對象同樣的功能,例如當成參數傳遞,當作返回值等。看看 Swift 語言帶來的眾多函數式編程的特性,就你知道這多 Cool 了。
響應式編程(React Programming),原來我們基于事件(Event)的處理方式都弱了,現在是基于輸入(在 ReactiveCocoa 里叫 Signal)的處理方式。輸入還可以通過函數式編程進行各種 Combine 或 Filter,盡顯各種靈活的處理。
無狀態(Stateless),狀態是函數的魔鬼,無狀態使得函數能更好地測試。
不可修改(Immutable),數據都是不可修改的,使得軟件邏輯簡單,也可以更好地測試。
結合了RAC庫,使得我們編寫的程序更加簡潔高效,維護性更高。
總結:
使用MVVM編寫代碼,雖然使層次增加了,但是提高了代碼的復用性及提高了代碼的可維護性,再結合RAC就更加牛B閃閃了。你們覺得呢?