自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

總結(jié)整理下一個(gè)快速開發(fā)MVVM框架

移動(dòng)開發(fā)
MVVM的出現(xiàn)主要是為了解決在開發(fā)過程中Controller越來(lái)越龐大的問題,變得難以維護(hù),所以MVVM把數(shù)據(jù)加工的任務(wù)從Controller中解放了出來(lái),使得Controller只需要專注于數(shù)據(jù)調(diào)配的工作,ViewModel則去負(fù)責(zé)數(shù)據(jù)加工并通過通知機(jī)制讓View響應(yīng)ViewModel的改變。

做iOS開發(fā)也有一段時(shí)間了,最近閑暇之余學(xué)習(xí)研究了下MVVM,每個(gè)人對(duì)架構(gòu)和設(shè)計(jì)模式都有不同的理解,在此記錄下我對(duì)MVVM的一些小見解,僅供參考,歡迎批評(píng)指正。

概述

MVVM的出現(xiàn)主要是為了解決在開發(fā)過程中Controller越來(lái)越龐大的問題,變得難以維護(hù),所以MVVM把數(shù)據(jù)加工的任務(wù)從Controller中解放了出來(lái),使得Controller只需要專注于數(shù)據(jù)調(diào)配的工作,ViewModel則去負(fù)責(zé)數(shù)據(jù)加工并通過通知機(jī)制讓View響應(yīng)ViewModel的改變。

MVVM是基于胖Model的架構(gòu)思路建立的,然后在胖Model中拆出兩部分:Model和ViewModel。ViewModel本質(zhì)上算是Model層(因?yàn)槭桥諱odel里面分出來(lái)的一部分),所以View并不適合直接持有ViewModel,因?yàn)閂iewModel有可能并不是只服務(wù)于特定的一個(gè)View,使用更加松散的綁定關(guān)系能夠降低ViewModel和View之間的耦合度。

還有一個(gè)讓人很容易忽略的問題,大部分國(guó)內(nèi)外資料闡述MVVM的時(shí)候都是這樣排布的:

  1. ViewViewModel Model 

造成了MVVM不需要Controller的錯(cuò)覺,現(xiàn)在似乎發(fā)展成業(yè)界開始出現(xiàn)MVVM是不需要Controller的聲音了。其實(shí)MVVM是一定需要Controller的參與的,雖然MVVM在一定程度上弱化了Controller的存在感,并且給Controller做了減負(fù)瘦身(這也是MVVM的主要目的)。但是,這并不代表MVVM中不需要Controller,MMVC和MVVM他們之間的關(guān)系應(yīng)該是這樣:

  1. View  C  ViewModel Model 

所以使用MVVM之后,就不需要Controller的說(shuō)法是不正確的。嚴(yán)格來(lái)說(shuō)MVVM其實(shí)是MVCVM。從中可以得知,Controller夾在View和ViewModel之間做的其中一個(gè)主要事情就是將View和ViewModel進(jìn)行綁定。在邏輯上,Controller知道應(yīng)當(dāng)展示哪個(gè)View,Controller也知道應(yīng)當(dāng)使用哪個(gè)ViewModel,然而View和ViewModel它們之間是互相不知道的,所以Controller就負(fù)責(zé)控制他們的綁定關(guān)系,所以叫Controller/控制器就是這個(gè)原因。

前面扯了那么多,其實(shí)歸根結(jié)底就是一句話:在MVC的基礎(chǔ)上,把C拆出一個(gè)ViewModel專門負(fù)責(zé)數(shù)據(jù)處理的事情,就是MVVM。然后,為了讓View和ViewModel之間能夠有比較松散的綁定關(guān)系,于是我們使用ReactiveCocoa,KVO,Notification,block,delegate和target-action都可以用來(lái)做數(shù)據(jù)通信,從而來(lái)實(shí)現(xiàn)綁定,但都不如ReactiveCocoa提供的RACSignal來(lái)的優(yōu)雅,如果不用ReactiveCocoa,綁定關(guān)系可能就做不到那么松散那么好,但并不影響它還是MVVM。

MVVM(View-ViewManger-C-ViewModel-Model)

  • View - 用來(lái)呈現(xiàn)用戶界面
  • ViewManger - 用來(lái)處理View的常規(guī)事件,負(fù)責(zé)管理View
  • Controller - 負(fù)責(zé)ViewManger和ViewModel之間的綁定,負(fù)責(zé)控制器本身的生命周期。
  • ViewModel - 存放各種業(yè)務(wù)邏輯和網(wǎng)絡(luò)請(qǐng)求
  • Model - 用來(lái)呈現(xiàn)數(shù)據(jù) 

這種設(shè)計(jì)的目的是保持View和Model的高度純潔,提高可擴(kuò)展性和復(fù)用度。在日常開發(fā)中,ViewModel是為了拆分Controller業(yè)務(wù)邏輯而存在的,所以ViewModel需要提供公共的服務(wù)接口,以便為Controller提供數(shù)據(jù)。而ViewManger的作用相當(dāng)于一個(gè)小管家,幫助Controller來(lái)分別管理每個(gè)subView,ViewManger負(fù)責(zé)接管來(lái)自View的事件,也負(fù)責(zé)接收來(lái)自Controller的模型數(shù)據(jù),而View進(jìn)行自己所負(fù)責(zé)的視圖數(shù)據(jù)綁定工作。Controller則是***的大家長(zhǎng),負(fù)責(zé)將ViewModel和ViewManger進(jìn)行綁定,進(jìn)行數(shù)據(jù)轉(zhuǎn)發(fā)工作。把合適的數(shù)據(jù)模型分發(fā)給合適的視圖管理者。

??日常開發(fā)中,往往一個(gè)視圖頁(yè)面交由一個(gè)控制器進(jìn)行管理,而一個(gè)頁(yè)面上又有N個(gè)小的子頁(yè)面,這就要求我們來(lái)對(duì)這些視圖進(jìn)行合適的分層處理,拆分視圖,將這些視圖進(jìn)行封裝,將復(fù)雜View抽象成獨(dú)立的類,不必暴露出具體的實(shí)現(xiàn)細(xì)節(jié)。這樣做的好處是,簡(jiǎn)化應(yīng)用層的層級(jí)復(fù)雜度,同時(shí)也方便進(jìn)行管理,視圖結(jié)構(gòu)就會(huì)變得很清晰。子視圖具體的內(nèi)部事件,可通過代理模式或者Block交由ViewManger處理,因?yàn)橐晥D是可以復(fù)用的,而其中的事件響應(yīng)代碼往往是根據(jù)不同的業(yè)務(wù)是有差異的。所以可能會(huì)有下面兩種情況出現(xiàn):

  • View很純潔,需要復(fù)用View,若業(yè)務(wù)邏輯變化則切換ViewManger。
  • ViewManger也比較純潔,若業(yè)務(wù)邏輯不變,而View需要大變,則切換View即可,保證View中的protocol或者block一致即可<***是通過協(xié)議提前規(guī)范好>。

這樣就實(shí)現(xiàn)了互相的封裝,兩者之間只通過protocol或者block進(jìn)行交流通信,降低了代碼的耦合度。盡量使用protocol和category來(lái)制定對(duì)象之間的通信規(guī)范,來(lái)降低代碼的侵入性。

這樣的架構(gòu)設(shè)計(jì),就像一條生產(chǎn)線,ViewModel進(jìn)行數(shù)據(jù)的采集和加工,Controller則進(jìn)行數(shù)據(jù)的裝配和轉(zhuǎn)發(fā)工作,ViewManger進(jìn)行接收轉(zhuǎn)發(fā)分配來(lái)的數(shù)據(jù),從而進(jìn)行負(fù)責(zé)View的展示工作和管理View的事件。這樣,不管哪個(gè)環(huán)節(jié),都是可以更換的,同時(shí)也提高了復(fù)用性。

架構(gòu)講解

以上圖做為講解demo,最然很簡(jiǎn)單,但是也能夠很好的闡述了,理解思想才是最重要的。 首先我們來(lái)拆分這個(gè)頁(yè)面,***個(gè)為控制器。暫且命名為MyController,上面有兩個(gè)直接子視圖,按鈕MyBtn和頁(yè)面比較復(fù)雜的子視圖MyView,MyView中有MyViewBtn1和MyViewBtn2還有一個(gè)MyViewLabel視圖。 具體結(jié)構(gòu)如下:

??界面分析完了,現(xiàn)在可以進(jìn)行代碼的架構(gòu)工作了。 首先需要建立一個(gè)ViewModel,使它能夠源源不斷的進(jìn)行數(shù)據(jù)的生產(chǎn),并提供數(shù)據(jù)給MyController;然后建立一個(gè)ViewManger負(fù)責(zé)管理MyView,當(dāng)然,Model模型數(shù)據(jù)必不可少。這些工作完成之后,代碼結(jié)構(gòu)變?yōu)椋?/p>

控制器中的代碼結(jié)構(gòu)如下圖:

當(dāng)用戶點(diǎn)擊MyBtn按鈕觸發(fā)動(dòng)作時(shí),控制器就會(huì)就將ViewMode中加載的數(shù)據(jù)模型轉(zhuǎn)發(fā)分配給ViewManger中的sui_model屬性接收。

  1. - (IBAction)clickBtnAction:(UIButton *)sender { 
  2.    self.thirdViewManger.sui_model = [self.viewModel getRandomData]; 

其中,MyViewModel中的加載代碼如下,如上所述,它的工作就是分解以前控制器做的一些事情。

  1. - (void)vm_getDataSuccessHandler:(void (^)())successHandler { 
  2.    // 博客中省略,查看詳細(xì)請(qǐng)參考demo 
  3.   
  4. - (instancetype)getRandomData { 
  5.     if (self.dataArrayList.count > 0) { 
  6.         u_int32_t index = arc4random_uniform((u_int32_t)self.dataArrayList.count); 
  7.         return self.dataArrayList[index]; 
  8.     } 
  9.     return nil; 

MyViewManger中的代碼如下,它實(shí)現(xiàn)了MVVMViewMangerProtocol協(xié)議的三個(gè)方法:

  1. // 此方法用來(lái)接收處理來(lái)自所管理View的一些事件。 
  2. - (void)handleViewMangerWithSubView:(UIView *)subView 
  3. // 此方法將view的父視圖傳遞過來(lái),用來(lái)布局當(dāng)前View 
  4. - (void)handleViewMangerWithSuperView:(UIView *)superView 
  5. // 根據(jù)所傳入的view和info信息分別實(shí)現(xiàn)具體的方法 
  6. - (void)handleViewMangerActionWithView:(UIView *)view info:(NSString *)info 
  1. - (void)handleViewMangerWithSubView:(UIView *)subView { 
  2.     __weak typeof(self.thirdView) weakThirdView =  self.thirdView; 
  3.     __weak typeof(self) weakSelf = self; 
  4.       
  5.     // btnClickBlock 
  6.     weakThirdView.btnClickBlock = ^() { 
  7.         [weakSelf handleViewMangerActionWithView:weakThirdView info:@"click"]; 
  8.     }; 
  9.       
  10.     // btnJumpBlock 
  11.     weakThirdView.btnJumpBlock = ^() { 
  12.         [weakSelf handleViewMangerActionWithView:weakThirdView info:@"jump"]; 
  13.     }; 
  14.   
  15. - (void)handleViewMangerWithSuperView:(UIView *)superView { 
  16.     self.thirdView.frame = CGRectMake(066, [UIScreen mainScreen].bounds.size.width, 200); 
  17.     [superView addSubview:self.thirdView]; 
  18.   
  19. - (void)handleViewMangerActionWithView:(UIView *)view info:(NSString *)info { 
  20.     if ([info isEqualToString:@"click"]) { 
  21.         [view configureViewWithCustomObj:self.sui_model]; 
  22.     } else { 
  23.         FirstVC *firstVC = [UIViewController svv_viewControllerWithStoryBoardName:@"Main" identifier:@"FirstVCID"]; 
  24.         [view.sui_currentVC.navigationController pushViewController:firstVC animated:YES]; 
  25.     } 

MyView中的代碼如下,主要是負(fù)責(zé)管理自身的內(nèi)部控件視圖,并根據(jù)業(yè)務(wù)邏輯需要定義了一些基本事件,通過交給ViewManger來(lái)實(shí)現(xiàn):

  1. - (IBAction)testBtnClick:(UIButton *)sender { 
  2.     if (self.btnClickBlock) { 
  3.         self.btnClickBlock(); 
  4.     } 
  5.   
  6. - (IBAction)jumpOtherVC:(UIButton *)sender { 
  7.     if (self.btnJumpBlock) { 
  8.         self.btnJumpBlock(); 
  9.     } 
  10.   
  11. // 根據(jù)傳入的model配置需要顯示的內(nèi)容 
  12. - (void)configureViewWithCustomObj:(id)obj { 
  13.     if (!obj) return
  14.     ThirdModel *thirdModel = (ThirdModel *)obj; 
  15.     self.testLabel.text = thirdModel.title; 

這樣把各個(gè)部分區(qū)分開來(lái),是不是感覺代碼結(jié)構(gòu)十分清晰了呢,當(dāng)然可以根據(jù)個(gè)人習(xí)慣來(lái)進(jìn)行修改,代碼實(shí)現(xiàn)因人而異,但是思想確是互通的。把合適的業(yè)務(wù)邏輯交給最合適的對(duì)象去處理實(shí)現(xiàn),只需要遵守這么一個(gè)基本原則就可以了。

至于是否采用更輕量級(jí)的ViewController做法,即 通過將各個(gè) protocol 的實(shí)現(xiàn)挪到 ViewController 之外,來(lái)為 ViewController 瘦身 ,眾口不一。以UITableView為例,我的做法是:

  • 如果只是在頁(yè)面上進(jìn)行簡(jiǎn)單的展示,并不設(shè)計(jì)負(fù)責(zé)的業(yè)務(wù)邏輯時(shí),會(huì)將UITableViewDelegate與UITableViewDataSource單獨(dú)放到一個(gè)Handler鐘進(jìn)行處理,抽象出tableHander,由MVVMTableDataDelegate進(jìn)行負(fù)責(zé)管理;

  • 當(dāng)然,事實(shí)上,實(shí)際開發(fā)中,每個(gè)tableView頁(yè)面都很復(fù)雜,有很多邏輯要處理,這時(shí)候只能考慮將protocol重新請(qǐng)回Controller中了,因?yàn)閂iew層與ViewController層本身是持有與被持有的依賴關(guān)系,所以任何類作為ViewController的類內(nèi)實(shí)例來(lái)實(shí)現(xiàn)協(xié)議回調(diào),實(shí)際上都是在跨層調(diào)用,所以,隨著時(shí)間和業(yè)務(wù)邏輯的愈來(lái)愈復(fù)雜,就注定要以額外的接口為代價(jià),換言之,ViewController 的內(nèi)聚性變差了。

總之,具體情況具體分析,采用最合適的方式來(lái)處理應(yīng)對(duì)不同的問題。兵來(lái)將擋,水來(lái)土掩。本文的相關(guān)Demo見github(https://github.com/lovemo/MVVMFramework),實(shí)現(xiàn)的功能并不復(fù)雜,僅供參考,歡迎補(bǔ)充。

責(zé)任編輯:倪明 來(lái)源: CocoaChina
相關(guān)推薦

2010-04-29 09:20:27

WEB開發(fā)

2013-10-08 10:22:14

2015-10-29 09:35:12

BAT趨勢(shì)數(shù)據(jù)

2014-06-17 10:57:09

2019-03-19 19:19:19

Facebook微信轉(zhuǎn)型

2011-10-31 10:17:47

開發(fā)平臺(tái)

2009-03-28 09:22:12

MID移動(dòng)OS

2022-02-13 15:49:15

WebAssemblKubernetes容器

2015-08-03 14:06:44

2019-04-15 11:00:46

框架Node.JS開發(fā)

2013-01-17 10:09:50

JavaSpring

2021-08-11 18:23:08

數(shù)據(jù)平臺(tái)IT

2011-03-17 15:01:11

Oracle

2013-01-14 14:28:29

汽車App開發(fā)商

2012-03-29 09:22:56

云計(jì)算私有云開發(fā)

2022-04-13 18:40:59

Python開發(fā)

2013-03-20 10:21:07

2018-05-20 15:54:22

2018-05-13 09:45:53

共享經(jīng)濟(jì)

2015-10-19 10:11:00

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)