談?wù)凪VC和MVVM

工作到現(xiàn)在,對代碼稍微有點認(rèn)識,if else 會寫那么點。今天就和大家談?wù)勊斫獾腗VC,以及現(xiàn)在比較流行的MVVM。首先我們應(yīng)該明白,計算機實現(xiàn)一個功能核心代碼就那么點。也許我們經(jīng)常會聽到對于同一個問題,菜鳥的實現(xiàn)的真的就是幾行,可是大牛卻多出了很多文件。這個是為什么?因為大牛的“經(jīng)驗”比較多。。。這里面最主要的目的就是為了維護和可擴展。在設(shè)計模式里面,如果你能遵循單一原則,你的代碼就已經(jīng)很好了。

MVC

做iOS開發(fā),一直被教導(dǎo)一定要按MVC模式開發(fā)??墒荕VC到底是神馬?至少在我工作初也不懂是咋回事!如果網(wǎng)上一搜就是千篇一律的M是數(shù)據(jù)模型,V是視圖,C是控制器。然后巴拉巴拉的講他們之間是怎么通信的。然并無卵用!iOS的MVC展現(xiàn)形式還是有點特殊的,特別是controller和view緊密在一起,controller還必須負(fù)責(zé)view的展示。在服務(wù)器端,view根據(jù)model直接生成HTML,然后直接扔給瀏覽器去渲染和展示,通過Ajax或者js post告訴服務(wù)器controller view的響應(yīng)事件,controller真的做的只是業(yè)務(wù)數(shù)據(jù)的處理,出來的結(jié)果其實還是數(shù)據(jù),根本沒有去做UI相關(guān)的事情。也可以說服務(wù)器根本就沒有view。。但它有個瀏覽器,幫他管理著view和controller之間的交互。而在我們iOS中,controller可不僅僅只是處理數(shù)據(jù)了,還負(fù)責(zé)view的管理以及事件的傳遞。 MVC本質(zhì)就是將數(shù)據(jù)展示和數(shù)據(jù)進行進行隔離,提高代碼的復(fù)用性和擴展性。好吧,我也說點并無什么卵用的。

看看斯坦福老爺爺?shù)囊粡垐D:

這就是我們所認(rèn)識的MVC。我們可以看到,Controller可以和Model通信,也可以和View進行通信。繼續(xù)看Controller和Model的關(guān)系,綠色的箭頭代表Controller可以直接進行對Model進行訪問,也就是說Model對于Controller來說就是透明的。但是Model并不知道Controller是誰。如果Model發(fā)生了變化,那么就通過Notification和KVO的方式傳遞給Controller。同樣的Controller和View之間也是這種關(guān)系,View對Controller來說就是 透明的。Controller可以直接根據(jù)Model決定View的展示。View如果接受響應(yīng)事件則通過delegate,target-action,block等方式告訴Controller的狀態(tài)變化。Controller進行業(yè)務(wù)的處理,然后再控制View的展示。

到這里你會發(fā)現(xiàn)Model和View并不能直接的進行通信,都必須通過Controller。那這樣Model和View就是相互獨立的。View只負(fù)責(zé)頁面的展示,Model只是數(shù)據(jù)的存儲,那么也就達(dá)到了解耦和重用的目的。

說這么多不如幾行代碼來的實在。我們以一個簡單的例子來看下:

我們假設(shè)蘋果根據(jù)買iPhone的人給予不同的優(yōu)惠,學(xué)生優(yōu)惠20%,it民工優(yōu)惠50%,其他不優(yōu)惠。

//客戶類

typedef NS_ENUM(NSInteger, CustomerType) {
    CustomerTypeStudent,
    CustomerTypeiT,
    CustomerTypeOther,
};

@interface Customer : NSObject

@property (nonatomic, assign) CustomerType customerType;

@end

//iPhone類

@interface iPhone : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *price;

@end

//VC類

@interface ViewController ()

@property (nonatomic, strong) iPhone *iphone;
@property (nonatomic, strong) Customer *customer;

@property (weak, nonatomic) IBOutlet UILabel *lblName;
@property (weak, nonatomic) IBOutlet UILabel *lblPrice;
@property (weak, nonatomic) IBOutlet UILabel *lblDiscount;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    self.title = @"手機優(yōu)惠";

    self.lblName.text = self.iphone.name;
    self.lblPrice.text = self.iphone.price;

    if (self.customer.customerType == CustomerTypeStudent) {
        self.lblDiscount.text = @"優(yōu)惠20%";
    }
    else if (self.customer.customerType == CustomerTypeiT) {
        self.lblDiscount.text = @"優(yōu)惠50%";
    }
    else {
        self.lblDiscount.text = @"沒有優(yōu)惠";
    }
}

@end

這個就是我們最正常的開發(fā),我們的邏輯都是在vc里面寫的。這樣寫有木有錯呢?一點沒錯,controller本來就是用來處理業(yè)務(wù)的。由于這個例子比較簡單,只是做了個優(yōu)惠判斷,所以我們看不出有啥壞處。有點開發(fā)經(jīng)驗的都知道,如果業(yè)務(wù)復(fù)雜起來,再加上其他亂七八糟的驗證,controller就會變得很大,越來越難以維護。這個也是MVC比較明顯的缺點。

MVVM

既然controller越來越臃腫,越來越難以維護,我們怎么去優(yōu)化和瘦身呢?回頭再仔細(xì)看看我們所謂的業(yè)務(wù)邏輯,是干什么的?無非就是根據(jù)幾個數(shù)據(jù)得出一個數(shù)據(jù)用來控制view的顯示。比如展示的是什么文案,按鈕能不能響應(yīng),頁面能不能跳轉(zhuǎn)等等。那MVVM就干了這件事,幫忙分擔(dān)一下controller里面的部分業(yè)務(wù)邏輯。MVVM更合理的應(yīng)該叫做MV-CM。

這個時候,controller將不再直接和真實的model進行綁定了,而通過ViewModel,viewModel進行持有真實的Model。

我們來看看剛剛那例子怎么修改:

//新建一個viewModel
//.h文件

@interface viewModel : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *price;
@property (nonatomic, strong) NSString *discount;

- (id)initWithCustomer:(Customer *)customer iphone:(iPhone *)iphone;

@end

//.m文件

@interface viewModel ()

@property (nonatomic, strong) iPhone *iphone;
@property (nonatomic, strong) Customer *customer;

@end

@implementation viewModel

- (id)initWithCustomer:(Customer *)customer iphone:(iPhone *)iphone
{
    if (self = [super init]) {
        _customer = customer;
        _iphone = iphone;
        [self bindData];
    }
    return self;
}

- (void)bindData
{
    self.name = _iphone.name;
    self.price = _iphone.price;

    if (self.customer.customerType == CustomerTypeStudent) {
        self.discount = @"優(yōu)惠20%";
    }
    else if (self.customer.customerType == CustomerTypeiT) {
        self.discount = @"優(yōu)惠50%";
    }
    else {
        self.discount = @"沒有優(yōu)惠";
    }
}

@end

//VC

@interface ViewController ()

@property (nonatomic, strong) viewModel *viewModel;

@property (weak, nonatomic) IBOutlet UILabel *lblName;
@property (weak, nonatomic) IBOutlet UILabel *lblPrice;
@property (weak, nonatomic) IBOutlet UILabel *lblDiscount;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    self.title = @"手機優(yōu)惠";

    self.lblName.text = self.viewModel.name;
    self.lblPrice.text = self.viewModel.price;
    self.lblDiscount.text = self.viewModel.discount;

}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

@end

看到修改完的代碼,你會發(fā)現(xiàn)VC里面已經(jīng)省去了不少的代碼。一切都和viewModel進行交流。這里我只是展示一個最簡單的數(shù)據(jù)展示,如果有其他響應(yīng)事件,是需要viewModel開放方法來進行處理的,并要通知VC處理結(jié)果的。

關(guān)于MVVM的優(yōu)點:

  • 方便測試

    在MVC下,Controller基本是無法測試的,里面混雜了個各種邏輯,而且分散在不同的地方。有了MVVM我們就可以測試?yán)锩娴膙iewModel,來驗證我們的處理結(jié)果對不對(Xcode7的測試已經(jīng)越來越完善了)。

  • 便于代碼的移植

    比如iOS里面有iPhone版本和iPad版本,除了交互展示不一樣外,業(yè)務(wù)邏輯的model是一致的。這樣,我們就可以以很小的代價去開發(fā)另一個app。(以前做公司iPad的時候就深深感覺到,全部在VC里面是多么的痛苦和重新開發(fā)一個沒有啥區(qū)別)。

  • 兼容MVC

    MVVM是MVC的一個升級版,目前的MVC也可以很快的轉(zhuǎn)換到MVVM這個模式。VC可以省去一大部分展示邏輯。

缺點:

  • 類會增多

    每個VC都附帶一個viewModel,類的數(shù)量*2

  • viewModel會越來越龐大

    我們把邏輯給了viewModel,那勢必Model也會變得很復(fù)雜,里面的屬性和方法越來越多??赡苤貙懙姆椒ū容^多,因為涉及到一些數(shù)據(jù)的轉(zhuǎn)換以及和controller之間的通信。

  • 調(diào)用復(fù)雜度增加

    由于數(shù)據(jù)都是從viewModel來,想想突然來了一個新人,一看代碼,不知道真實的模型是誰。比如常用tableview的數(shù)據(jù)源,一般都是一個數(shù)組,如果不斷的通過viewModel去取,溝通上沒有那么直接。況且每封一層,意味著要寫很多代碼去融合他們的轉(zhuǎn)換。

最后說下ReactiveCocoa這個框架,這個雖然和MVVM經(jīng)常一起出現(xiàn),這個框架主要是幫我們實現(xiàn)model和view的綁定機制。后面會有文章來介紹它。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容