iOS 關于MVC和MVVM設計模式的那些事

一磷雇、概述
  • 在 iOS 開發(fā)中,MVC(Model View Controller)是構建iOS App的標準模式涩澡,是蘋果推薦的一個用來組織代碼的權威范式咕娄。Apple甚至是這么說的。在MVC下奈梳,所有的對象被歸類為一個Model杈湾,一個View,和一個Controller攘须。Model持有數(shù)據(jù)漆撞,View顯示與用戶交互的界面,而ViewController調解ModelView之間的交互∮谥妫現(xiàn)在浮驳,MVC 依然是目前主流客戶端編程框架,但同時它也被調侃成Massive View Controller(重量級視圖控制器)捞魁,想必開發(fā)者在開發(fā)中無可避免被下面幾個問題所困擾:

    • 厚重的ViewController
    • 遺失的網(wǎng)絡邏輯(無立足之地)
    • 較差的可測試性
  • 為了避免和解決上述問題的產(chǎn)生至会,從MVC引申出來一種維護性較強耦合性低的新的架構MVVM(Model View View-Mode)谱俭,MVVM正式規(guī)范了視圖和控制器緊耦合的性質奉件,并引入新的組件宵蛀。MVVM主要目的是為了分離視圖(View)模型(Model)

  • 本文只是分享一下筆者對MVCMVVM的一些見解县貌,在此拋磚引玉术陶,希望能為存在對MVCMVVM迷茫的廣大開發(fā)者提供一點思路,少走一些彎路煤痕,填補一些細坑梧宫。文章僅供大家參考,若有不妥之處摆碉,還望不吝賜教塘匣,歡迎批評指正。

二兆解、MVC(Model View Controller)
  1. MVC之間的關系
    任何一個正經(jīng)開發(fā)過軟件的人都熟悉MVC馆铁,它意思是Model View Controller, 是一個在復雜應用設計中組織代碼的公認模式跑揉,它們之間的結構關系如下:
    MVC示意圖.png

我們看到的只是一個蘋果 **典型的MVC ** 設置锅睛。view將用戶交互通知給controllerview controller通過更新model來反應狀態(tài)的改變历谍。model(通常使用Key-Value-Observation)通知controller來更新他們負責的view现拒。大多數(shù)iOS應用程序的代碼使用這種方式來組織。然而望侈,典型的MVC架構不適用于當下的iOS開發(fā)印蔬。盡管從技術上看ViewController 是相互獨立的,但事實上它們幾乎總是結對出現(xiàn)脱衙,一個 View 只能與一個 Controller 進行匹配侥猬,反之亦然。既然如此捐韩,那我們?yōu)楹尾徽?guī)化它們的連接:

MVC示意圖2.png

因此退唠,M-VC 可能是對 iOS 開發(fā)中的 MVC模式更為準確的解讀,同時更也準確地描述了我們?nèi)粘i_發(fā)可能已經(jīng)編寫的 MVC 代碼荤胁,但它并沒有做太多事情來解決 iOS 應用中日益增長的重量級視圖控制器的問題瞧预。(PS:躺槍了沒...)

舉例說明:


M-VC_Example.png

若假設筆者利用MVC的設計模式來開發(fā)此界面,那想必是這樣的仅政。

  • M:SUGoods(商品模型Model)
  • V:SUGoodsCell(展示商品數(shù)據(jù)的View垢油,自定義的 UITableViewCell)
  • C:SUHomeViewController (首頁控制器Controller)

控制器(SUHomeViewController)代碼實現(xiàn)

- (void) requestRemoteData
{
   // 1.發(fā)起網(wǎng)絡請求,獲取到服務器的數(shù)據(jù)圆丹,并將其轉化成模型數(shù)據(jù)(`SUGoods`)
   // 2.添加到數(shù)據(jù)源(`dataSource`)
   // 3.最后刷新表格`[self.tableView reloadData]`滩愁,配置`SUGoodsCel`l即可
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    SUGoodsCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Goods"];
    cell.goods = self.dataSource[indexPath.row];
    return cell;
}

View(SUGoodsCell)代碼實現(xiàn)

SUGoodsCell.h
@class SUGoods;
@interface SUGoodsCell : UITableViewCell
@property (nonatomic, strong) SUGoods *goods;
@end

SUGoodsCell.m
@implementation SUGoodsCell
- (void)setGoods:(SUGoods *)goods
{
     _goods = goods
     /// config data ....
}
@end 

都寫到這份上了,大家用腳趾頭想想辫封,這個SUGoodsCell硝枉,正是由View直接來調用Model玖瘸,所以事實上典型的MVC的原則已經(jīng)違背了,但是這種情況是一直發(fā)生的甚至于人們不覺得這里有哪些不對檀咙。如果嚴格遵守MVC的話雅倒,你會把對cell的設置放在Controller中,不向View傳遞一個Model對象弧可,這樣就會大大增加Controller的體積蔑匣。所以說,這哪里是典型的MVC設計模式棕诵,這分明是M-VC設計模式呀裁良。簡而言之,在理想的世界里校套,MVC也許工作的很好价脾。然而,我們生活在真實的世界笛匙,謝謝(PS:讓夢想實現(xiàn)的最好的方式侨把,就是醒來!C盟铩G锉)。

  1. MVC的弊端
    MVC的利弊大家想必是有目共睹的蠢正,Massive View Controller的說法也并非空穴來風的骇笔。讓我們一起探討MVC的弊端,剖析問題產(chǎn)生原因嚣崭,打造一個輕量級的ViewController笨触,明確MVC設計模式中各個角色的職責。
  • 厚重的View Controller
    M:模型model的對象通常非常的簡單雹舀。根據(jù)Apple的文檔芦劣,model應包括數(shù)據(jù)操作數(shù)據(jù)的業(yè)務邏輯。而在實踐中葱跋,model層往往非常薄持寄,不管怎樣,model層的業(yè)務邏輯不應被拖入到controller娱俺。
    V:視圖view通常是UIKit控件(component稍味,這里根據(jù)習慣譯為控件)或者編碼定義的UIKit控件的集合。View的如何構建(PS:IB或者手寫界面)何必讓Controller知曉荠卷,同時View不應該直接引用model(PS:現(xiàn)實中模庐,你懂的!)油宜,并且僅僅通過IBAction事件引用controller掂碱。業(yè)務邏輯很明顯不歸入view怜姿,視圖本身沒有任何業(yè)務。
    C:控制器controller疼燥。Controller是app的“膠水代碼”:協(xié)調模型和視圖之間的所有交互沧卢。控制器負責管理他們所擁有的視圖的視圖層次結構醉者,還要響應視圖的loading但狭、appearingdisappearing等等撬即,同時往往也會充滿我們不愿暴露的model的模型邏輯以及不愿暴露給視圖的業(yè)務邏輯立磁。
    網(wǎng)絡數(shù)據(jù)的請求及后續(xù)處理肢专,本地數(shù)據(jù)庫操作佑吝,以及一些帶有工具性質輔助方法都加大了Massive View Controller的產(chǎn)生。

  • 遺失(無處安放)的網(wǎng)絡邏輯
    蘋果使用的MVC的定義是這么說的:所有的對象都可以被歸類為一個model球及,一個view粒竖,或是一個controller颅崩。
    你可能試著把它放在Model對象里,但是也會很棘手温圆,因為網(wǎng)絡調用應該使用異步挨摸,這樣如果一個網(wǎng)絡請求比持有它的model生命周期更長,事情將變的復雜岁歉。顯然View里面做網(wǎng)絡請求那就更格格不入了,因此只剩下Controller了膝蜈。若這樣锅移,這又加劇了Massive View Controller的問題。若不這樣饱搏,何處才是網(wǎng)絡邏輯的家呢非剃?

  • 較差的可測試性
    由于View Controller混合了視圖處理邏輯和業(yè)務邏輯,分離這些成分的單元測試成了一個艱巨的任務推沸。若一個Massive View Controller有上萬行代碼备绽,要你編寫個單元測試,我敢保證鬓催,你不是想寫肺素,你是想死,分分鐘填表走人宇驾。

三倍靡、MVVM(Model View View-Mode)

一種可以很好地解決Massive View Controller問題的辦法就是將 Controller 中的展示邏輯抽取出來,放置到一個專門的地方课舍,而這個地方就是 viewModel 塌西。MVVM衍生于MVC他挎,是對 MVC 的一種演進,它促進了 UI 代碼與業(yè)務邏輯的分離捡需。它正式規(guī)范了視圖和控制器緊耦合的性質办桨,并引入新的組件。他們之間的結構關系如下:

MVVM示意圖.png

  • MVVM 的基本概念

    • MVVM 中站辉,viewview controller正式聯(lián)系在一起崔挖,我們把它們視為一個組件
    • viewview controller 都不能直接引用model,而是引用視圖模型(viewModel
    • viewModel 是一個放置用戶輸入驗證邏輯庵寞,視圖顯示邏輯狸相,發(fā)起網(wǎng)絡請求和其他代碼的地方
    • 使用MVVM會輕微的增加代碼量,但總體上減少了代碼的復雜性
  • MVVM 的注意事項

    • view 引用viewModel 捐川,但反過來不行(即不要在viewModel中引入#import UIKit.h脓鹃,任何視圖本身的引用都不應該放在viewModel中)(PS:基本要求,必須滿足
    • viewModel 引用model古沥,但反過來不行
  • MVVM 的使用建議

    • MVVM 可以兼容你當下使用的MVC架構瘸右。
    • MVVM 增加你的應用的可測試性。
    • MVVM 配合一個綁定機制效果最好(PS:ReactiveCocoa你值得擁有)岩齿。
    • viewController 盡量不涉及業(yè)務邏輯太颤,讓 viewModel 去做這些事情。
    • viewController 只是一個中間人盹沈,接收 view 的事件龄章、調用 viewModel 的方法、響應 viewModel 的變化乞封。
    • viewModel 絕對不能包含視圖 view(UIKit.h)做裙,不然就跟 view 產(chǎn)生了耦合,不方便復用和測試肃晚。
    • viewModel之間可以有依賴锚贱。
    • viewModel避免過于臃腫,否則重蹈Controller的覆轍关串,變得難以維護拧廊。
  • MVVM 的優(yōu)勢

    • 低耦合:View 可以獨立于Model變化和修改,一個 viewModel 可以綁定到不同的 View
    • 可重用性:可以把一些視圖邏輯放在一個 viewModel里面晋修,讓很多 view 重用這段視圖邏輯
    • 獨立開發(fā):開發(fā)人員可以專注于業(yè)務邏輯和數(shù)據(jù)的開發(fā) viewModel吧碾,設計人員可以專注于頁面設計
    • 可測試:通常界面是比較難于測試的,而 MVVM 模式可以針對 viewModel來進行測試
  • MVVM 的弊端

    • 數(shù)據(jù)綁定使得Bug 很難被調試飞蚓。你看到界面異常了滤港,有可能是你 View 的代碼有 Bug,也可能是 Model 的代碼有問題。數(shù)據(jù)綁定使得一個位置的 Bug 被快速傳遞到別的位置溅漾,要定位原始出問題的地方就變得不那么容易了山叮。
    • 對于過大的項目,數(shù)據(jù)綁定和數(shù)據(jù)轉化需要花費更多的內(nèi)存(成本)添履。主要成本在于:
      • 數(shù)組內(nèi)容的轉化成本較高:數(shù)組里面每項都要轉化成Item對象屁倔,如果Item對象中還有類似數(shù)組,就很頭疼暮胧。
      • 轉化之后的數(shù)據(jù)在大部分情況是不能直接被展示的锐借,為了能夠被展示,還需要第二次轉化往衷。
      • 只有在API返回的數(shù)據(jù)高度標準化時钞翔,這些對象原型(Item)的可復用程度才高,否則容易出現(xiàn)類型爆炸席舍,提高維護成本布轿。
      • 調試時通過對象原型查看數(shù)據(jù)內(nèi)容不如直接通過NSDictionary/NSArray直觀。
      • 同一API的數(shù)據(jù)被不同View展示時来颤,難以控制數(shù)據(jù)轉化的代碼汰扭,它們有可能會散落在任何需要的地方。
四福铅、總結
  • MVC的設計模式也并非是病入膏肓萝毛,無藥可救的架構,最起碼目前MVC設計模式仍舊是iOS開發(fā)的主流框架滑黔,存在即合理笆包。針對文章所述的弊端,我們依舊有許多可行的方法去避免和解決拷沸,從而打造一個輕量級的ViewController色查。
  • MVVMMVC的升級版,完全兼容當前的MVC架構撞芍,MVVM雖然促進了UI 代碼與業(yè)務邏輯的分離,一定程度上減輕了ViewController的臃腫度跨扮,但是ViewViewModel之間的數(shù)據(jù)綁定使得 MVVM變得復雜和難用了序无,如果我們不能更好的駕馭兩者之間的數(shù)據(jù)綁定,同樣會造成Controller 代碼過于復雜衡创,代碼邏輯不易維護的問題帝嗡。
  • 一個輕量級的ViewController是基于MVCMVVM模式進行代碼職責的分離而打造的。MVCMVVM有優(yōu)點也有缺點璃氢,但缺點在他們所帶來的好處面前時不值一提的哟玷。他們的低耦合性,封裝性,可測試性巢寡,可維護性和多人協(xié)作便利大大提高了開法效率喉脖。
  • 同時,我們需要保持的是一個擁抱變化的心抑月,以及理性分析的態(tài)度树叽。在新技術的面前,不盲從谦絮,也不守舊题诵,一切的決策都應該建立在認真分析的基礎上,這樣才能應對技術的變化层皱。
五性锭、期待
  1. 文章若對您有點幫助,請給個喜歡??叫胖,畢竟碼字不易草冈;若對您沒啥幫助,請給點建議??臭家,切記學無止境疲陕。
  2. 針對文章所述內(nèi)容,閱讀期間任何疑問钉赁;請在文章底部批評指正蹄殃,我會火速解決和修正問題。
  3. GitHub地址:https://github.com/CoderMikeHe
六你踩、實戰(zhàn)篇
七诅岩、參考鏈接
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市带膜,隨后出現(xiàn)的幾起案子吩谦,更是在濱河造成了極大的恐慌,老刑警劉巖膝藕,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件式廷,死亡現(xiàn)場離奇詭異,居然都是意外死亡芭挽,警方通過查閱死者的電腦和手機滑废,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來袜爪,“玉大人蠕趁,你說我怎么就攤上這事⌒凉荩” “怎么了俺陋?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我腊状,道長诱咏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任寿酌,我火速辦了婚禮胰苏,結果婚禮上,老公的妹妹穿的比我還像新娘醇疼。我一直安慰自己硕并,他們只是感情好,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布秧荆。 她就那樣靜靜地躺著倔毙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪乙濒。 梳的紋絲不亂的頭發(fā)上陕赃,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音颁股,去河邊找鬼么库。 笑死,一個胖子當著我的面吹牛甘有,可吹牛的內(nèi)容都是我干的诉儒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼亏掀,長吁一口氣:“原來是場噩夢啊……” “哼忱反!你這毒婦竟也來了?” 一聲冷哼從身側響起滤愕,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤温算,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后间影,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體注竿,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年魂贬,在試婚紗的時候發(fā)現(xiàn)自己被綠了蔓搞。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡随橘,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出锦庸,到底是詐尸還是另有隱情机蔗,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站萝嘁,受9級特大地震影響梆掸,放射性物質發(fā)生泄漏。R本人自食惡果不足惜牙言,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一酸钦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧咱枉,春花似錦卑硫、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至亿乳,卻和暖如春硝拧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背葛假。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工障陶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人聊训。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓抱究,卻偏偏與公主長得像,于是被迫代替她去往敵國和親魔眨。 傳聞我的和親對象是個殘疾皇子媳维,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355

推薦閱讀更多精彩內(nèi)容