MVC的低耦合性、高重用性、可維護性等優勢顯而易見,使得本來複雜的代碼與界面的交互變得簡單、清晰、明瞭,開發者能夠把更多的精力放在前端界面的設計上,而不用絞盡腦汁去思考究竟應該如何使界面獲得同步,這樣減輕了設計壓力,也從另外一方面使用戶獲得更多更好的享受體驗。縱觀iOS經典Native App的全部應用軟件,幾乎都具備一個很大特色,那就是「炫」。清新的畫面配以簡單的手勢操做,顛覆着用戶的思惟方式,小巧精悍。前端
MVC是構建iOS app的標準模式。可是,各位朋友們,若是你已經使用過MVC一段時間,我以爲愈來愈厭倦MVC的一些缺點。在本文,我將重溫一下MVC是什麼,詳述它的缺點,而且告訴你一個新的方式來架構你的app:Model-View-ViewModel。 ios
MVC便是Model-VIew-Controller三個英文單詞的縮寫,中文翻譯爲模型-視圖-控制器。MVC並不是只有ios應用軟件獨有的應用開發模式,它被普遍應用在許多軟件(尤爲是中大型軟件)的開發上。MVC把軟件系統分爲三個部分:Model,View,Controller。Model至關於應用的底層,應用在功能上的實現徹底依賴於Model,打個比方,若是是一臺電腦的話,Model就是你機箱裏的全部東西:cpu,內存,硬盤,顯卡等的一個集合,你沒必要看到它們,但它們必不可少;Controller就是控制器,它控制Model與View的交互,它將M和V捆綁在一塊兒,將你的操做傳達給Model,再控制View將其表現出來。View至關於電腦的圖形界面,將Model的運行結果可視化地呈現給用戶,你在屏幕上看到的一切均可以歸類於View。編程
在cocoa中,你的程序中的每個object(對象)都將明顯地僅屬於這三部分中的一個,而徹底不屬於另外兩個。所以,用MVC開發的應用軟件更易於進行維護和修改,不用由於底層的Model出了問題而去影響表層的View。MVC雖然把三部分獨立了出來,但三部分之間仍然存在聯繫,但就以下圖所示,Model與View之間是徹底獨立的,二者各自運行,以Controller爲橋樑進行交互,並不發生直接關聯。網絡
在這種架構下,View 是無狀態的,在 Model 變化的時候它只是簡單的被 Controller 重繪;就像網頁同樣,點擊了一個新的連接,整個網頁就從新加載。儘管這種架構能夠在 iOS 應用裏面實現,可是因爲 MVC 的三種實體被緊密耦合着,每一種實體都和其餘兩種有着聯繫,因此即使是實現了也沒有什麼意義。這種緊耦合還戲劇性的減小了它們被重用的可能,這恐怕不是你想要在本身的應用裏面看到的。綜上,傳統 MVC 的例子我以爲也沒有必要去寫了。架構
傳統的 MVC 已經不適合當下的 iOS 開發了。app
View 和 Model 之間是相互獨立的,它們只經過 Controller 來相互聯繫。有點惱人的是 Controller 是重用性最差的,由於咱們通常不會把冗雜的業務邏輯放在 Model 裏面,那就只能放在 Controller 裏了。框架
理論上看這麼作貌似挺簡單的,可是你有沒有以爲有點不對勁?你甚至聽過有人把 MVC 叫作重控制器模式。另外 關於 ViewController 瘦身 已經成爲iOS 開發者們熱議的話題了。爲何 Apple 要沿用只是作了一點點改進的傳統 MVC 架構呢?異步
Cocoa MVC 鼓勵你去寫重控制器是由於 View 的整個生命週期都須要它去管理,Controller 和 View 很難作到相互獨立。雖然你能夠把控制器裏的一些業務邏輯和數據轉換的工做交給 Model,可是你再想把負擔往 View 裏面分攤的時候就沒辦法了;由於 View 的主要職責就只是講用戶的操做行爲交給Controller 去處理而已。因而 ViewController 最終就變成了全部東西的代理和數據源,甚至還負責網絡請求的發起和取消。單元測試
MVC如下幾點是真的讓人很頭疼!!測試
厚重的View Controller
因爲大量的代碼被放進view controller,致使他們變的至關臃腫。在iOS中有的view controller裏綿延成千上萬行代碼的事並非前所未見的。這些超重app的突出狀況包括:厚重的View Controller很難維護(因爲其龐大的規模);包含幾十個屬性,使他們的狀態難以管理;遵循許多協議(protocol),致使協議的響應代碼和controller的邏輯代碼混淆在一塊兒。
厚重的view controller很難測試,無論是手動測試或是使用單元測試,由於有太多可能的狀態。將代碼分解成更小的多個模塊一般是件好事。
遺失的網絡邏輯
蘋果使用的MVC的定義是這麼說的:全部的對象均可以被歸類爲一個model,一個view,或是一個controller。就這些。那麼把網絡代碼放哪裏?和一個API通訊的代碼應該放在哪兒?
你可能試着把它放在model對象裏,可是也會很棘手,由於網絡調用應該使用異步,這樣若是一個網絡請求比持有它的model生命週期更長,事情將變的複雜。顯然也不該該把網絡代碼放在view裏,所以只剩下controller了。這一樣是個壞主意,由於這加重了厚重View Controller的問題。
那麼應該放在那裏呢?顯然MVC的3大組件根本沒有適合放這些代碼的地方。
較差的可測試性
MVC的另外一個大問題是,它不鼓勵開發人員編寫單元測試。因爲view controller混合了視圖處理邏輯和業務邏輯,分離這些成分的單元測試成了一個艱鉅的任務。大多數人選擇忽略這個任務,那就是不作任何測試。
定義模糊的「Manage」
以前我提到了view controller能夠管理試圖的層次結構;view controller有一個「view」屬性,而且能夠經過IBOutlet訪問視圖的任何子視圖。當有不少outlet時這樣作不易於擴展,在某種意義上,最好不要使用子視圖控制器(child view controller)來幫助管理子視圖(subview)。
要點在哪?驗證用戶輸入的業務邏輯應納入controller仍是model呢?
在這裏有多個模糊的標準,彷佛沒有人能徹底達成一致。貌似不管如何,view和對應的controller都牢牢的耦合在一塊兒,總之,仍是會把它們當成一個組件來對待。
Hey!如今有個點子...
Model-View-ViewModel
在理想的世界裏,MVC也許工做的很好。然而,咱們生活在真實的世界。既然咱們已經詳細說明了MVC在典型場景中的問題,那讓咱們看一看一個可供替換的選擇:Model-View-ViewModel。
MVVM來自微軟,不過不要堅持反對它。MVVM和MVC很像。它正式規範了視圖和控制器緊耦合的性質,並引入新的組件。
在MVVM裏,view和view controller正式聯繫在一塊兒,咱們把它們視爲一個組件。視圖view仍然不能直接引用模型model,固然controller也不能。相反,他們引用視圖模型view model。
view model是一個放置用戶輸入驗證邏輯,視圖顯示邏輯,發起網絡請求和其餘各類各樣的代碼的極好的地方。有一件事情不該納入view model,那就是任何視圖自己的引用。view model的概念同時適用於於iOS和OS X。(換句話說,不要在view model中使用 #import UIKit.h)
因爲展現邏輯(presentation logic)放在了view model中(好比model的值映射到一個格式化的字符串),視圖控制器自己就會再也不臃腫。當你開始使用MVVM的最好方式是,能夠先將一小部分邏輯放入視圖模型,而後當你逐漸習慣於使用這個範式的時候再遷移更多的邏輯到視圖模型中。
使用MVVM的iOS app是高度可測試的;由於view model包含了全部的展現邏輯而且不會引用view,因此它能夠經過編程方式充分測試。雖然有衆多的hack技術參與到測試Core Data模型,但使用MVVM寫的app能夠進行充分的單元測試。
以個人經驗,使用MVVM會輕微的增長代碼量,但整體上減小了代碼的複雜性。這是一個划算的交易。