iOS平臺上的MVVM模式(譯文)

轉載自:http://www.teehanlax.com/blog/model-view-viewmodel-for-ios/ios

Written by Ash Furrow on January 14,2014 in Development設計模式

若是你在iOS平臺上有必定開發經驗,必定據說過Model-View-Controller,或稱MVC模式,MVC是構建iOS應用的標準設計模式。但實際開發中,MVC暴露出許多的缺陷。網絡

經過這篇文章,我會介紹什麼是MVC,以及MVC的缺陷。對於如何解決MVC的這些缺陷,我會介紹一種全新設計模式:Model-View-ViewModel,即MVVM。mvc

1 MVC模式及其缺陷

1.1 MVC模式簡介

蘋果官方稱MVC設計模式(簡稱MVC)是iOS應用設計的最佳模式。異步

在MVC中,任何對象均可被歸爲模型對象、視圖對象或控制器對象。模型對象(Model Object,簡稱模型)持有程序數據;視圖對象(View Object,簡稱視圖)負責用戶交互;控制器對象(Controller Object,簡稱控制器)則做爲模型和視圖溝通的媒介。mvvm

視圖將用戶輸入轉交給控制器,由控制器按照相應請求通知模型進行更新,模型將自身數據變化通知(一般經過KVO的途徑)控制器,最後控制器操做視圖進行相應的更新(以下圖所示):單元測試

mvc

模型一般十分簡潔,大多數狀況下它們由Core Data管理。根據蘋果的描述,模型中封裝了數據以及對數據的操做代碼。實際工做中使用的模型對象一般都很小,但數據操做代碼時常會被耦合到控制器中。測試

視圖是UIKit對象或自定義對象,它是程序中的可視部分,一般存在於.xib文件或storyboard中,好比按鈕或標籤。視圖不該同模型直接交互,而只能經過控制器的IBAction事件進行間接交互,而且非視圖邏輯不該寫在視圖中。設計

控制器至關於膠水代碼,將模型和視圖粘合在一塊兒。控制器負責控制視圖的加載,顯示,隱藏等。在控制器中還存在控制模型的代碼,以及那些既不屬於模型對象又不屬於視圖對象的代碼,從而引出MVC模式的第一個缺陷。對象

1.2 MVC的缺陷

1.2.1 臃腫的控制器

控制器的功能決定了其內部既包含視圖控制又包含模型控制,這使得控制器十分臃腫。

千上萬行代碼擠在一個控制器內,致使代碼不易維護。好比一個控制器有數十個屬性,要管理它的各類狀態就十分困難。再好比一個控制器接受了若干協議,那其中就可能既包含協議方法代碼,又包含控制器自身的控制邏輯。

另一個結果是程序不易測試(不管是手動測試仍是單元測試),由於控制器擁有太多不一樣的狀態,沒法將全部狀態都覆蓋到。

1.2.2 網絡邏輯無處可放

若是程序中全部對象都被納入MVC,那麼問題來了:網絡代碼應歸爲哪一類?API通訊代碼又歸爲哪一類?

假設網絡代碼被放在模型中,因爲網絡請求必須支持異步完成,若是模型已經消失,而網絡請求還在繼續,那這個問題就複雜了。

另外,網絡代碼不可能放在視圖中,那就只剩一個地方了:控制器。但把網絡代碼放在控制器中的作法很糟糕,這樣會加重以前提到的問題:臃腫的控制器。

那麼,到底該將網絡代碼放在何處?MVC中並無提供解決方案。

1.2.3 代碼難以測試

MVC另一個問題是它不利於測試。控制器中混合了操做邏輯和業務邏輯,想要將這兩者分離進行測試會十分困難。固然,許多人都有辦法忽略這個問題,即不進行任何測試。

1.2.4 模糊的管理

控制器管理着一個視圖樹,經過IBOutlet還能夠訪問任意子視圖,但當使用控制器管理大量子視圖時,用outlet來訪問就顯得過於複雜了,一個解決辦法是添加子控制器管理子視圖。

不管怎麼作,控制器和對應的視圖都緊密耦合,固然也能夠把它們兩者就看作一個總體。

不過,能夠看看下面這個辦法。

2 MVVM模式

也許在理想狀態下MVC會有很好的效果,但現實中它卻不盡如人意。

咱們已經對MVC模式有了詳細瞭解,下面就介紹它的替代方案:Model-View-ViewModel(MVVM)模式。

MVVM由微軟公司提出(先不要對它產生偏見),它和MVC模式有許多相同之處。MVVM將視圖和控制器的耦合部分抽取出來,從而引入一個新的部分,即View-Model(VM)。

mvvm

在MVVM模式下,視圖及控制器形式上關聯在一塊兒,故可將兩者視爲一個總體。視圖仍不會同模型直接交互,但控制器也沒有同模型直接交互,取而代之的是視圖模型(ViewModel)。

諸如驗證用戶輸入請求、視圖的顯示邏輯、剝離網絡請求或其餘相似代碼,將它們放在視圖模型中再合適不過了,而且視圖模型中沒有對視圖的直接引用。

視圖模型中封裝的代碼既能夠工做在iOS下,也能夠工做在OSX下(換句話說就是不要在視圖模型中引入和具體平臺有關的內容,如#import UIKit.h)。

因爲將視圖邏輯——好比說將模型中的某些值映射爲一個字符串的操做,都放在了視圖模型中,故大大下降了控制器的複雜程度和它與其餘部分的耦合程度。

使用MVVM的最大好處是,你能夠先放入一小部分邏輯到視圖模型中,隨着對模式瞭解的深刻,慢慢再將其餘代碼遷移到其中。

MVVM模式對測試十分友好。因爲視圖模型中包含了全部的顯示邏輯,而且沒有任何對於視圖的直接引用,故徹底能夠自動化測試,而且使用MVVM的程序能夠充分地運行單元測試。

就我使用MVVM的經驗來看,這種模式會形成代碼量稍稍提高,可是代碼複雜程度獲得極大下降,孰優孰劣一目瞭然。

本文中屢次在不一樣地方使用到了「通知」和「更新」,但沒有說明如何進行這樣的操做。你能夠在MVC模式中使用KVO來進行這樣的操做,但代碼會很快變得難以管理。實際工做中,更傾向於在MVVM中使用ReactiveCocoa來將全部的部分關聯到一塊兒。

相關文章
相關標籤/搜索