久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

iOS應(yīng)用架構(gòu)談(二):View層的組織和調(diào)用方案(中)

 沒(méi)原創(chuàng)_去搜索 2015-06-29
轉(zhuǎn)自: http://www./cn/articles/ios-app-arch-2-2


iOS客戶端應(yīng)用架構(gòu)看似簡(jiǎn)單,,但實(shí)際上要考慮的事情不少。本文作者將以系列文章的形式來(lái)回答iOS應(yīng)用架構(gòu)中的種種問(wèn)題,,本文是其中的第二篇,,主要講View層的組織和調(diào)用方案。中篇主要討論MVC,、MVCS,、MVVM、VIPER等架構(gòu)在iOS開(kāi)發(fā)中的應(yīng)用,。

關(guān)于MVC,、MVVM等一大堆思想

其實(shí)這些都是相對(duì)通用的思想,萬(wàn)變不離其宗的還是在開(kāi)篇里面我提到的那三個(gè)角色:數(shù)據(jù)管理者,,數(shù)據(jù)加工者,,數(shù)據(jù)展示者。這些五花八門的思想,,不外乎就是制訂了一個(gè)規(guī)范,,規(guī)定了這三個(gè)角色應(yīng)當(dāng)如何進(jìn)行數(shù)據(jù)交換。但同時(shí)這些也是爭(zhēng)議最多的話題,,所以我在這里來(lái)把幾個(gè)主流思想做一個(gè)梳理,,當(dāng)你在做View層架構(gòu)時(shí),能夠有個(gè)比較好的參考,。

MVC

MVC(Model-View-Controller)是最老牌的的思想,,老牌到4人幫的書(shū)里把它歸成了一種模式,其中Model就是作為數(shù)據(jù)管理者,,View作為數(shù)據(jù)展示者,,Controller作為數(shù)據(jù)加工者,Model和View又都是由Controller來(lái)根據(jù)業(yè)務(wù)需求調(diào)配,,所以Controller還負(fù)擔(dān)了一個(gè)數(shù)據(jù)流調(diào)配的功能,。正在我寫(xiě)這篇文章的時(shí)候,我看到InfoQ發(fā)了這篇文章,,里面提到了一個(gè)移動(dòng)開(kāi)發(fā)中的痛點(diǎn)是:對(duì)MVC架構(gòu)劃分的理解,。我當(dāng)時(shí)沒(méi)能夠去參加這個(gè)座談會(huì),也沒(méi)辦法發(fā)表個(gè)人意見(jiàn),,所以就只能在這里寫(xiě)寫(xiě)了,。

在iOS開(kāi)發(fā)領(lǐng)域,我們應(yīng)當(dāng)如何進(jìn)行MVC的劃分,?

這里面其實(shí)有兩個(gè)問(wèn)題:

  1. 為什么我們會(huì)糾結(jié)于iOS開(kāi)發(fā)領(lǐng)域中MVC的劃分問(wèn)題,?
  2. 在iOS開(kāi)發(fā)領(lǐng)域中,怎樣才算是劃分的正確姿勢(shì)?

為什么我們會(huì)糾結(jié)于iOS開(kāi)發(fā)領(lǐng)域中MVC的劃分問(wèn)題,?

關(guān)于這個(gè),,每個(gè)人糾結(jié)的點(diǎn)可能不太一樣,我也不知道當(dāng)時(shí)座談會(huì)上大家的觀點(diǎn),。但請(qǐng)?jiān)试S我猜一下:是不是因?yàn)閁IViewController中自帶了一個(gè)View,,且控制了View的整個(gè)生命周期(viewDidLoad,viewWillAppear...),而在常識(shí)中我們都知道Controller不應(yīng)該和View有如此緊密的聯(lián)系,,所以才導(dǎo)致大家對(duì)劃分產(chǎn)生困惑,?,下面我會(huì)針對(duì)這個(gè)猜測(cè)來(lái)給出我的意見(jiàn),。

在服務(wù)端開(kāi)發(fā)領(lǐng)域,Controller和View的交互方式一般都是這樣,,比如Yii:

  /*
        ...
            數(shù)據(jù)庫(kù)取數(shù)據(jù)
        ...
            處理數(shù)據(jù)
        ...
    */
    // 此處$this就是Controller
    $this->render("plan",array(
        'planList' => $planList,
        'plan_id' => $_GET['id'],
    ));

這里Controller和View之間區(qū)分得非常明顯,,Controller做完自己的事情之后,就把所有關(guān)于View的工作交給了頁(yè)面渲染引擎去做,,Controller不會(huì)去做任何關(guān)于View的事情,,包括生成View,這些都由渲染引擎代勞了,。這是一個(gè)區(qū)別,,但其實(shí)服務(wù)端View的概念和Native應(yīng)用View的概念,真正的區(qū)別在于:從概念上嚴(yán)格劃分的話,,服務(wù)端其實(shí)根本沒(méi)有View,,拜HTTP協(xié)議所賜,我們平時(shí)所討論的View只是用于描述View的字符串(更實(shí)質(zhì)的應(yīng)該稱之為數(shù)據(jù)),,真正的View是瀏覽器,。。

所以服務(wù)端只管生成對(duì)View的描述,,至于對(duì)View的長(zhǎng)相,,UI事件監(jiān)聽(tīng)和處理,都是瀏覽器負(fù)責(zé)生成和維護(hù)的,。但是在Native這邊來(lái)看,,原本屬于瀏覽器的任務(wù)也逃不掉要自己做。那么這件事情由誰(shuí)來(lái)做最合適,?蘋果給出的答案是:UIViewController,。

鑒于蘋果在這一層做了很多艱苦卓絕的努力,讓iOS工程師們不必親自去實(shí)現(xiàn)這些內(nèi)容,。而且,,它把所有的功能都放在了UIView上,并且把UIView做成不光可以展示UI,,還可以作為容器的一個(gè)對(duì)象,。

看到這兒你明白了嗎,?UIView的另一個(gè)身份其實(shí)是容器!UIViewController中自帶的那個(gè)view,,它的主要任務(wù)就是作為一個(gè)容器,。如果它所有的相關(guān)命名都改成ViewContainer,那么代碼就會(huì)變成這樣:

- (void)viewContainerDidLoad
{
    [self.viewContainer addSubview:self.label];
    [self.viewContainer addSubview:self.tableView];
    [self.viewContainer addSubview:self.button];
    [self.viewContainer addSubview:self.textField];
}
... ...

僅僅改了個(gè)名字,,現(xiàn)在是不是感覺(jué)清晰了很多,?如果再要說(shuō)詳細(xì)一點(diǎn),我們平常所認(rèn)為的服務(wù)端MVC是這樣劃分的:

但事實(shí)上,,整套流程的MVC劃分是這樣:

由圖中可以看出,,我們服務(wù)端開(kāi)發(fā)在這個(gè)概念下,其實(shí)只涉及M和C的開(kāi)發(fā)工作,,瀏覽器作為View的容器,,負(fù)責(zé)View的展示和事件的監(jiān)聽(tīng)。那么對(duì)應(yīng)到iOS客戶端的MVC劃分上面來(lái),,就是這樣:

唯一區(qū)別在于,,View的容器在服務(wù)端,是由Browser負(fù)責(zé),,在整個(gè)網(wǎng)站的流程中,,這個(gè)容器放在Browser是非常合理的。在iOS客戶端,,View的容器是由UIViewController中的view負(fù)責(zé),,我也覺(jué)得蘋果做的這個(gè)選擇是非常正確明智的。

因?yàn)闉g覽器和服務(wù)端之間的關(guān)系非常松散,,而且他們分屬于兩個(gè)不同陣營(yíng),,服務(wù)端將對(duì)View的描述生成之后,交給瀏覽器去負(fù)責(zé)展示,,然而一旦view上有什么事件產(chǎn)生,,基本上是很少傳遞到服務(wù)器(也就是所謂的Controller)的(要傳也可以:AJAX),都是在瀏覽器這邊把事情都做掉,,所以在這種情況下,,View容器就適合放在瀏覽器(V)這邊。

但是在iOS開(kāi)發(fā)領(lǐng)域,,雖然也有讓View去監(jiān)聽(tīng)事件的做法,,但這種做法非常少,都是把事件回傳給Controller,,然后Controller再另行調(diào)度,。所以這時(shí)候,View的容器放在Controller就非常合適。Controller可以因?yàn)椴煌录漠a(chǎn)生去很方便地更改容器內(nèi)容,,比如加載失敗時(shí),,把容器內(nèi)容換成失敗頁(yè)面的View,無(wú)網(wǎng)絡(luò)時(shí),,把容器頁(yè)面換成無(wú)網(wǎng)絡(luò)的View等等,。

在iOS開(kāi)發(fā)領(lǐng)域中,怎樣才算是MVC劃分的正確姿勢(shì),?

這個(gè)問(wèn)題其實(shí)在上面已經(jīng)解答掉一部分了,,那么這個(gè)問(wèn)題的答案就當(dāng)是對(duì)上面問(wèn)題的一個(gè)總結(jié)吧。

M應(yīng)該做的事:

  • 給ViewController提供數(shù)據(jù)
  • 給ViewController存儲(chǔ)數(shù)據(jù)提供接口
  • 提供經(jīng)過(guò)抽象的業(yè)務(wù)基本組件,,供Controller調(diào)度

C應(yīng)該做的事:

  • 管理View Container的生命周期
  • 負(fù)責(zé)生成所有的View實(shí)例,,并放入View Container
  • 監(jiān)聽(tīng)來(lái)自View與業(yè)務(wù)有關(guān)的事件,通過(guò)與Model的合作,,來(lái)完成對(duì)應(yīng)事件的業(yè)務(wù),。

V應(yīng)該做的事:

  • 響應(yīng)與業(yè)務(wù)無(wú)關(guān)的事件,并因此引發(fā)動(dòng)畫(huà)效果,,點(diǎn)擊反饋(如果合適的話,盡量還是放在View去做)等,。
  • 界面元素表達(dá)

我通過(guò)與服務(wù)端MVC劃分的對(duì)比來(lái)回答了這兩個(gè)問(wèn)題,,之所以這么做,是因?yàn)槲抑烙泻芏鄆OS工程師之前是從服務(wù)端轉(zhuǎn)過(guò)來(lái)的,。我也是這樣,,在進(jìn)安居客之前,我也是做服務(wù)端開(kāi)發(fā)的,,在學(xué)習(xí)iOS的過(guò)程中,,我也曾經(jīng)對(duì)iOS領(lǐng)域的MVC劃分問(wèn)題產(chǎn)生過(guò)疑惑,我疑惑的點(diǎn)就是前面開(kāi)篇我猜測(cè)的點(diǎn),。如果有人問(wèn)我iOS中應(yīng)該怎么做MVC的劃分,,我就會(huì)像上面這么回答。

MVCS

蘋果自身就采用的是這種架構(gòu)思路,,從名字也能看出,,也是基于MVC衍生出來(lái)的一套架構(gòu)。從概念上來(lái)說(shuō),,它拆分的部分是Model部分,,拆出來(lái)一個(gè)Store。這個(gè)Store專門負(fù)責(zé)數(shù)據(jù)存取,。但從實(shí)際操作的角度上講,,它拆開(kāi)的是Controller。

這算是瘦Model的一種方案,瘦Model只是專門用于表達(dá)數(shù)據(jù),,然后存儲(chǔ),、數(shù)據(jù)處理都交給外面的來(lái)做。MVCS使用的前提是,,它假設(shè)了你是瘦Model,,同時(shí)數(shù)據(jù)的存儲(chǔ)和處理都在Controller去做。所以對(duì)應(yīng)到MVCS,,它在一開(kāi)始就是拆分的Controller,。因?yàn)镃ontroller做了數(shù)據(jù)存儲(chǔ)的事情,就會(huì)變得非常龐大,,那么就把Controller專門負(fù)責(zé)存取數(shù)據(jù)的那部分抽離出來(lái),,交給另一個(gè)對(duì)象去做,這個(gè)對(duì)象就是Store,。這么調(diào)整之后,,整個(gè)結(jié)構(gòu)也就變成了真正意義上的MVCS。

關(guān)于胖Model和瘦Model

我在面試和跟別人聊天時(shí),,發(fā)現(xiàn)知道胖Model和瘦Model的概念的人不是很多,。大約兩三年前國(guó)外業(yè)界曾經(jīng)對(duì)此有過(guò)非常激烈的討論,主題就是Fat model, skinny controller?,F(xiàn)在關(guān)于這方面的討論已經(jīng)不多了,,然而直到今天胖Model和瘦Model哪個(gè)更好,業(yè)界也還沒(méi)有定論,,所以這算是目前業(yè)界懸而未解的一個(gè)爭(zhēng)議,。我很少看到國(guó)內(nèi)有討論這個(gè)的資料,所以在這里我打算補(bǔ)充一下什么叫胖Model什么叫瘦Model,。以及他們的爭(zhēng)論來(lái)源于何處,。

什么叫胖Model?

胖Model包含了部分弱業(yè)務(wù)邏輯,。胖Model要達(dá)到的目的是,,Controller從胖Model這里拿到數(shù)據(jù)之后,不用額外做操作或者只要做非常少的操作,,就能夠?qū)?shù)據(jù)直接應(yīng)用在View上,。舉個(gè)例子:

Raw Data:
    timestamp:1234567
FatModel:
    @property (nonatomic, assign) CGFloat timestamp;
    - (NSString *)ymdDateString; // 2015-04-20 15:16
    - (NSString *)gapString; // 3分鐘前、1小時(shí)前,、一天前,、2015-3-13 12:34
Controller:
    self.dateLabel.text = [FatModel ymdDateString];
    self.gapLabel.text = [FatModel gapString];

把timestamp轉(zhuǎn)換成具體業(yè)務(wù)上所需要的字符串,這屬于業(yè)務(wù)代碼,,算是弱業(yè)務(wù),。FatModel做了這些弱業(yè)務(wù)之后,,Controller就能變得非常skinny,Controller只需要關(guān)注強(qiáng)業(yè)務(wù)代碼就行了,。眾所周知,,強(qiáng)業(yè)務(wù)變動(dòng)的可能性要比弱業(yè)務(wù)大得多,弱業(yè)務(wù)相對(duì)穩(wěn)定,,所以弱業(yè)務(wù)塞進(jìn)Model里面是沒(méi)問(wèn)題的,。另一方面,弱業(yè)務(wù)重復(fù)出現(xiàn)的頻率要大于強(qiáng)業(yè)務(wù),,對(duì)復(fù)用性的要求更高,,如果這部分業(yè)務(wù)寫(xiě)在Controller,類似的代碼會(huì)灑得到處都是,,一旦弱業(yè)務(wù)有修改(弱業(yè)務(wù)修改頻率低不代表就沒(méi)有修改),,這個(gè)事情就是一個(gè)災(zāi)難。如果塞到Model里面去,,改一處很多地方就能跟著改,,就能避免這場(chǎng)災(zāi)難。

然而其缺點(diǎn)就在于,,胖Model相對(duì)比較難移植,,雖然只是包含弱業(yè)務(wù),但好歹也是業(yè)務(wù),,遷移的時(shí)候很容易拔出蘿卜帶出泥,。另外一點(diǎn),MVC的架構(gòu)思想更加傾向于Model是一個(gè)Layer,,而不是一個(gè)Object,,不應(yīng)該把一個(gè)Layer應(yīng)該做的事情交給一個(gè)Object去做,。最后一點(diǎn),,軟件是會(huì)成長(zhǎng)的,F(xiàn)atModel很有可能隨著軟件的成長(zhǎng)越來(lái)越Fat,,最終難以維護(hù),。

什么叫瘦Model?

瘦Model只負(fù)責(zé)業(yè)務(wù)數(shù)據(jù)的表達(dá),,所有業(yè)務(wù)無(wú)論強(qiáng)弱一律扔到Controller,。瘦Model要達(dá)到的目的是,盡一切可能去編寫(xiě)細(xì)粒度Model,,然后配套各種helper類或方法來(lái)對(duì)弱業(yè)務(wù)做抽象,,強(qiáng)業(yè)務(wù)依舊交給Controller。舉個(gè)例子:

Raw Data:
{
    "name":"casa",
    "sex":"male",
}
SlimModel:
    @property (nonatomic, strong) NSString *name;
    @property (nonatomic, strong) NSString *sex;
Helper:
    #define Male 1;
    #define Female 0;
    + (BOOL)sexWithString:(NSString *)sex;
Controller:
    if ([Helper sexWithString:SlimModel.sex] == Male) {
        ...
    }

由于SlimModel跟業(yè)務(wù)完全無(wú)關(guān),,它的數(shù)據(jù)可以交給任何一個(gè)能處理它數(shù)據(jù)的Helper或其他的對(duì)象,,來(lái)完成業(yè)務(wù),。在代碼遷移的時(shí)候獨(dú)立性很強(qiáng),很少會(huì)出現(xiàn)拔出蘿卜帶出泥的情況,。另外,,由于SlimModel只是數(shù)據(jù)表達(dá),對(duì)它進(jìn)行維護(hù)基本上是0成本,,軟件膨脹得再厲害,,SlimModel也不會(huì)大到哪兒去。

缺點(diǎn)就在于,,Helper這種做法也不見(jiàn)得很好,,這里有一篇文章批判了這個(gè)事情。另外,,由于Model的操作會(huì)出現(xiàn)在各種地方,,SlimModel在一定程度上違背了DRY(Don't Repeat Yourself)的思路,Controller仍然不可避免在一定程度上出現(xiàn)代碼膨脹,。

我的態(tài)度,?嗯,我會(huì)在本門心法這一節(jié)里面說(shuō),。

說(shuō)回來(lái),,MVCS是基于瘦Model的一種架構(gòu)思路,把原本Model要做的很多事情中的其中一部分關(guān)于數(shù)據(jù)存儲(chǔ)的代碼抽象成了Store,,在一定程度上降低了Controller的壓力,。

MVVM

MVVM去年在業(yè)界討論得非常多,無(wú)論國(guó)內(nèi)還是國(guó)外都討論得非常熱烈,,尤其是在ReactiveCocoa這個(gè)庫(kù)成熟之后,,ViewModel和View的信號(hào)機(jī)制在iOS下終于有了一個(gè)相對(duì)優(yōu)雅的實(shí)現(xiàn)。MVVM本質(zhì)上也是從MVC中派生出來(lái)的思想,,MVVM著重想要解決的問(wèn)題是盡可能地減少Controller的任務(wù),。不管MVVM也好,MVCS也好,,他們的共識(shí)都是Controller會(huì)隨著軟件的成長(zhǎng),,變很大很難維護(hù)很難測(cè)試。只不過(guò)兩種架構(gòu)思路的前提不同,,MVCS是認(rèn)為Controller做了一部分Model的事情,,要把它拆出來(lái)變成Store,MVVM是認(rèn)為Controller做了太多數(shù)據(jù)加工的事情,,所以MVVM把數(shù)據(jù)加工的任務(wù)從Controller中解放了出來(lái),,使得Controller只需要專注于數(shù)據(jù)調(diào)配的工作,ViewModel則去負(fù)責(zé)數(shù)據(jù)加工并通過(guò)通知機(jī)制讓View響應(yīng)ViewModel的改變,。

MVVM是基于胖Model的架構(gòu)思路建立的,,然后在胖Model中拆出兩部分:Model和ViewModel,。關(guān)于這個(gè)觀點(diǎn)我要做一個(gè)額外解釋:胖Model做的事情是先為Controller減負(fù),然后由于Model變胖,,再在此基礎(chǔ)上拆出ViewModel,,跟業(yè)界普遍認(rèn)知的MVVM本質(zhì)上是為Controller減負(fù)這個(gè)說(shuō)法并不矛盾,因?yàn)榕諱odel做的事情也是為Controller減負(fù),。

另外,,我前面說(shuō)MVVM把數(shù)據(jù)加工的任務(wù)從Controller中解放出來(lái),跟MVVM拆分的是胖Model也不矛盾,。要做到解放Controller,,首先你得有個(gè)胖Model,然后再把這個(gè)胖Model拆成Model和ViewModel,。

那么MVVM究竟應(yīng)該如何實(shí)現(xiàn),?

這很有可能是大多數(shù)人糾結(jié)的問(wèn)題,我打算憑我的個(gè)人經(jīng)驗(yàn)試圖在這里回答這個(gè)問(wèn)題,,歡迎交流,。

在iOS領(lǐng)域大部分MVVM架構(gòu)都會(huì)使用ReactiveCocoa,但是使用ReactiveCocoa的iOS應(yīng)用就是基于MVVM架構(gòu)的嗎,?那當(dāng)然不是,,我覺(jué)得很多人都存在這個(gè)誤區(qū),我面試過(guò)的一些人提到了ReactiveCocoa也提到了MVVM,,但他們對(duì)此的理解膚淺得讓我忍俊不禁,。嗯,在網(wǎng)絡(luò)層架構(gòu)我會(huì)舉出不使用ReactiveCocoa的例子,,現(xiàn)在舉我感覺(jué)有點(diǎn)兒早,。

MVVM的關(guān)鍵是要有View Model!而不是ReactiveCocoa

注:MVVM要有ViewModel,,以及ReactiveCocoa帶來(lái)的信號(hào)通知效果,,在ReactiveCocoa里就是RAC等相關(guān)宏來(lái)實(shí)現(xiàn)。另外,,使用ReactiveCocoa能夠比較優(yōu)雅地實(shí)現(xiàn)MVVM模式,,就是因?yàn)橛蠷AC等相關(guān)宏的存在,。就像它的名字一樣Reactive-響應(yīng)式,,這也是區(qū)分MVVM的VM和MVC的C和MVP的P的一個(gè)重要方面。

ViewModel做什么事情,?就是把RawData變成直接能被View使用的對(duì)象的一種Model,。舉個(gè)例子:

 Raw Data:
        {
            (
                (123, 456),
                (234, 567),
                (345, 678)
            )
        }

這里的RawData我們假設(shè)是經(jīng)緯度,數(shù)字我隨便寫(xiě)的不要太在意,。然后你有一個(gè)模塊是地圖模塊,,把經(jīng)緯度數(shù)組全部都轉(zhuǎn)變成MKAnnotation或其派生類對(duì)于Controller來(lái)說(shuō)是弱業(yè)務(wù),,(記住,胖Model就是用來(lái)做弱業(yè)務(wù)的),,因此我們用ViewModel直接把它轉(zhuǎn)變成MKAnnotation的NSArray,,交給Controller之后Controller直接就可以用了。

嗯,,這就是ViewModel要做的事情,,是不是覺(jué)得很簡(jiǎn)單,看不出優(yōu)越性,?

安居客Pad應(yīng)用也有一個(gè)地圖模塊,,在這里我設(shè)計(jì)了一個(gè)對(duì)象叫做reformer(其實(shí)就是ViewModel),專門用來(lái)干這個(gè)事情,。那么這么做的優(yōu)越性體現(xiàn)在哪兒呢,?

安居客分三大業(yè)務(wù):租房、二手房,、新房,。這三個(gè)業(yè)務(wù)對(duì)應(yīng)移動(dòng)開(kāi)發(fā)團(tuán)隊(duì)有三個(gè)API開(kāi)發(fā)團(tuán)隊(duì),他們各自為政,,這就造成了一個(gè)結(jié)果:三個(gè)API團(tuán)隊(duì)回饋給移動(dòng)客戶端的數(shù)據(jù)內(nèi)容雖然一致,,但是數(shù)據(jù)格式是不一致的,也就是相同value對(duì)應(yīng)的key是不一致的,。但展示地圖的ViewController不可能寫(xiě)三個(gè),,所以肯定少不了要有一個(gè)API數(shù)據(jù)兼容的邏輯,這個(gè)邏輯我就放在reformer里面去做了,,于是業(yè)務(wù)流程就變成了這樣:

這么一來(lái),,原本復(fù)雜的MKAnnotation組裝邏輯就從Controller里面拆分了出來(lái),Controller可以直接拿著Reformer返回的數(shù)據(jù)進(jìn)行展示,。APIManager就屬于Model,,reformer就屬于ViewModel。具體關(guān)于reformer的東西我會(huì)放在網(wǎng)絡(luò)層架構(gòu)來(lái)詳細(xì)解釋,。Reformer此時(shí)扮演的ViewModel角色能夠很好地給Controller減負(fù),,同時(shí),維護(hù)成本也大大降低,,經(jīng)過(guò)reformer產(chǎn)出的永遠(yuǎn)都是MKAnnotation,,Controller可以直接拿來(lái)使用。

然后另外一點(diǎn),,還有一個(gè)業(yè)務(wù)需求是取附近的房源,,地圖API請(qǐng)求是能夠hold住這個(gè)需求的,那么其他地方都不用變,,在fetchDataWithReformer的時(shí)候換一個(gè)reformer就可以了,,其他的事情都交給reformer,。

那么ReactiveCocoa應(yīng)該扮演什么角色?

不用ReactiveCocoa也能MVVM,,用ReactiveCocoa能更好地體現(xiàn)MVVM的精髓,。前面我舉到的例子只是數(shù)據(jù)從API到View的方向,View的操作也會(huì)產(chǎn)生"數(shù)據(jù)",,只不過(guò)這里的"數(shù)據(jù)"更多的是體現(xiàn)在表達(dá)用戶的操作上,,比如輸入了什么內(nèi)容,那么數(shù)據(jù)就是text,、選擇了哪個(gè)cell,,那么數(shù)據(jù)就是indexPath。那么在數(shù)據(jù)從view走向API或者Controller的方向上,,就是ReactiveCocoa發(fā)揮的地方,。

我們知道,ViewModel本質(zhì)上算是Model層(因?yàn)槭桥諱odel里面分出來(lái)的一部分),,所以View并不適合直接持有ViewModel,,那么View一旦產(chǎn)生數(shù)據(jù)了怎么辦?扔信號(hào)扔給ViewModel,,用誰(shuí)扔,?ReactiveCocoa。

在MVVM中使用ReactiveCocoa的第一個(gè)目的就是如上所說(shuō),,View并不適合直接持有ViewModel,。第二個(gè)目的就在于,ViewModel有可能并不是只服務(wù)于特定的一個(gè)View,,使用更加松散的綁定關(guān)系能夠降低ViewModel和View之間的耦合度,。

那么在MVVM中,Controller扮演什么角色,?

大部分國(guó)內(nèi)外資料闡述MVVM的時(shí)候都是這樣排布的:View <-> ViewModel <-> Model,,造成了MVVM不需要Controller的錯(cuò)覺(jué),現(xiàn)在似乎發(fā)展成業(yè)界開(kāi)始出現(xiàn)MVVM是不需要Controller的,。的聲音了,。其實(shí)MVVM是一定需要Controller的參與的,雖然MVVM在一定程度上弱化了Controller的存在感,,并且給Controller做了減負(fù)瘦身(這也是MVVM的主要目的),。但是,這并不代表MVVM中不需要Controller,,MMVC和MVVM他們之間的關(guān)系應(yīng)該是這樣:

(來(lái)源:http://www./2014/12/06/reactivecocoa-mvvm-introduction/)

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,,因?yàn)樘O果本身并沒(méi)有提供一個(gè)比較適合這種情況的綁定方法。iOS領(lǐng)域里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。

在實(shí)際iOS應(yīng)用架構(gòu)中,,MVVM應(yīng)該出現(xiàn)在了大部分創(chuàng)業(yè)公司或者老牌公司新App的iOS應(yīng)用架構(gòu)圖中,,據(jù)我所知易寶支付旗下的某個(gè)iOS應(yīng)用就整體采用了MVVM架構(gòu),他們抽出了一個(gè)Action層來(lái)裝各種ViewModel,,也是屬于相對(duì)合理的結(jié)構(gòu),。

所以Controller在MVVM中,一方面負(fù)責(zé)View和ViewModel之間的綁定,,另一方面也負(fù)責(zé)常規(guī)的UI邏輯處理,。

VIPER

VIPER(View,Interactor,,Presenter,,Entity,Routing)。VIPER我并沒(méi)有實(shí)際使用過(guò),,我是在objc.io上第13期看到的,。

但凡出現(xiàn)一個(gè)新架構(gòu)或者我之前并不熟悉的新架構(gòu),有一點(diǎn)我能夠非??隙?,這貨一定又是把MVC的哪個(gè)部分給拆開(kāi)了(壞笑,做這種判斷的理論依據(jù)在第一篇文章里面我已經(jīng)講過(guò)了),。事實(shí)情況是VIPER確實(shí)拆了很多很多,,除了View沒(méi)拆,其它的都拆了,。

我提到的這兩篇文章關(guān)于VIPER都講得很詳細(xì),,一看就懂。但具體在使用VIPER的時(shí)候會(huì)有什么坑或者會(huì)有哪些爭(zhēng)議我不是很清楚,,硬要寫(xiě)這一節(jié)的話我只能靠YY,,所以我想想還是算了。如果各位讀者有誰(shuí)在實(shí)際App中采用VIPER架構(gòu)的或者對(duì)VIPER很有興趣的,,可以評(píng)論區(qū)里面提出來(lái),,我們交流一下。

編后語(yǔ)

為了更好地向讀者輸出更優(yōu)質(zhì)的內(nèi)容,,InfoQ將精選來(lái)自國(guó)內(nèi)外的優(yōu)秀文章,,經(jīng)過(guò)整理審校后,發(fā)布到網(wǎng)站,。本篇文章作者為田偉宇,,原文鏈接為Casa Taloyum。本文已由原作者授權(quán)InfoQ中文站轉(zhuǎn)載,。


感謝徐川對(duì)本文的審校,。

給InfoQ中文站投稿或者參與內(nèi)容翻譯工作,請(qǐng)郵件至editors@cn.,。也歡迎大家通過(guò)新浪微博(@InfoQ,,@丁曉昀),微信(微信號(hào):InfoQChina)關(guān)注我們,,并與我們的編輯和其他讀者朋友交流(歡迎加入InfoQ讀者交流群InfoQ好讀者),。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多