1. 程式人生 > >iOS MVC和MVVM架構

iOS MVC和MVVM架構

MVC 模式

MVC 概念

  • Modal 模型物件:模型物件封裝了應用程式的資料,並定義操控和處理該資料的邏輯和運算。模型(Model)實際上考慮的是“什麼”的問題,即你的程式是什麼?以紙牌匹配遊戲為例子,模型就是設計這個遊戲怎麼玩,花色匹配,數值匹配得多少分,等邏輯問題。以及這個遊戲裡的類,如:紙牌,牌堆等類都屬於模型裡面的東西。以上都是獨立於UI且在模型中的。
  • Controller 控制器物件:控制器(Controller)控制模型如何呈現在螢幕上,即弄清如何將這些牌顯示在螢幕上,然後將其用動畫的形式表現。
  • View 檢視物件:檢視物件是應用程式中使用者可以看見的物件。檢視(View)是控制器的侍從,是控制器要使用的類,用於構建UI。

MVC 各層之間的通訊

  • Controller要完全知道Model的內容,不受限制地訪問Model;相反,Model 通過 Notification 和 KVO 機制與 Controller 間接通訊。
  • Controller也能與View通訊,如通過outlet;相反View也能與Controller通訊,但是View是通用的,所以它不能對Controller的類知道得太多,只能以一種“盲”的方式去通訊,如關聯一個action、委託(delegate)協議。
  • Model 和 View 永遠不能相互通訊,只能通過 Controller 傳遞。

MVC的架構模式圖:

MVVM 模式

MVVM 概念

這個模式的核心是ViewModel,它是一種特殊的model型別,用於表示程式的UI狀態。它包含描述每個UI控制元件的狀態的屬性。例如,文字輸入域的當前文字,或者一個特定按鈕是否可用。它同樣暴露了檢視可以執行哪些行為,如按鈕點選或手勢。可以將ViewModel看作是檢視的模型(model-of-the-view)。MVVM模式中的三部分比MVC更加簡潔,下面是一些嚴格的限制:

  • View引用了ViewModel,但反過來不行。
  • ViewModel引用了Model,但反過來不行。

如果我們破壞了這些規則,便無法正確地使用MVVM。

View引用了ViewModel,但ViewModel沒有引用View,那ViewModel如何更新檢視呢?MVVM模式依賴於資料繫結,它是一個框架級別的特性,用於自動連線物件屬性和UI控制元件。

為什麼使用MVVM

iOS中,我們使用的大部分都是MVC架構。雖然MVC的層次明確,但是由於功能日益的增加、程式碼的維護,使得更多的程式碼被寫在了Controller中,這樣Controller需要做太多得事情,表示邏輯、業務邏輯,所以程式碼量非常的大,就顯得非常臃腫。。

為了給Controller瘦身,後來又從MVC衍生出了一種新的架構模式MVVM架構。

MVVM分別指什麼

MVVM就是在MVC的基礎上分離出業務處理的邏輯到ViewModel層,即:

Model層:請求的原始資料

View層:檢視展示,由ViewController來控制

ViewModel層:負責業務處理和資料轉化

簡單來說,就是API請求完資料,解析成Model,之後在ViewModel中轉化成能夠直接被檢視層使用的資料,交付給前端(View層)。

 

MVVM的架構模式圖:

例項

比如我們有一個需求:一個頁面,需要判斷使用者是否手動設定了使用者名稱。如果設定了,正常顯示使用者名稱;如果沒有設定,則顯示“匿名使用者123”這種格式。(雖然這些本應是伺服器端判斷的)

我們看看MVC和MVVM兩種架構都是怎麼實現這個需求的

MVC:

Model類:

#import <Foundation/Foundation.h>

@interface User : NSObject

@property (nonatomic, copy) NSString *userName;
@property (nonatomic, assign) NSInteger userId;

- (instancetype)initWithUserName:(NSString *)userName userId:(NSInteger)userId;

@end

@implementation User

- (instancetype)initWithUserName:(NSString *)userName userId:(NSInteger)userId {
    self = [super init];
    if (!self) return nil;
    _userName = userName;
    _userId   = userId;
    return self;
}

@end

ViewController類:

#import "HomeViewController.h"
#import "User.h"

@interface HomeViewController ()

@property (nonatomic, strong) UILabel *lb_userName;
@property (nonatomic, strong) User *user;

@end

@implementation HomeViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //建立User例項並初始化
    if (_user.userName.length > 0) {
        _lb_userName.text = _user.userName;
    } else {
        _lb_userName.text = [NSString stringWithFormat:@"匿名使用者%ld", _user.userId];
    }
}

@end

這裡我們需要將表示邏輯也放在ViewController中。

MVVM:

Model類:

#import <Foundation/Foundation.h>

@interface User : NSObject

@property (nonatomic, copy) NSString *userName;
@property (nonatomic, assign) NSInteger userId;

@end

ViewModel類:

宣告:

#import <Foundation/Foundation.h>
#import "User.h"

@interface UserViewModel : NSObject

@property (nonatomic, strong) User *user;
@property (nonatomic, copy) NSString *userName;

- (instancetype)initWithUserName:(NSString *)userName userId:(NSInteger)userId;

@end

實現:

#import "UserViewModel.h"

@implementation UserViewModel

- (instancetype)initWithUserName:(NSString *)userName userId:(NSInteger)userId {
    self = [super init];
    if (!self) return nil;
    _user = [[User alloc] initWithUserName:userName userId:userId];
    if (_user.userName.length > 0) {
        _userName = _user.userName;
    } else {
        _userName = [NSString stringWithFormat:@"匿名使用者%ld", _user.userId];
    }
    return self;
}

@end

Controller類:

#import "HomeViewController.h"
#import "UserViewModel.h"

@interface HomeViewController ()

@property (nonatomic, strong) UILabel *lb_userName;
@property (nonatomic, strong) UserViewModel *userViewModel;

@end

@implementation HomeViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    _userViewModel = [[UserViewModel alloc] initWithUserName:@"TonyStark" userId:123456];
    _lb_userName.text = _userViewModel.userName;
}

@end

可見,Controller中我們不需要再做多餘的判斷,那些表示邏輯我們已經移植到了ViewModel中,ViewController明顯輕量了很多。說白了,就是把原來ViewController層的業務邏輯和頁面邏輯等剝離出來放到ViewModel層。

總結:

  • MVVM同MVC一樣,目的都是分離Model與View,但是它更好的將表示邏輯分離出來,減輕了Controller的負擔;
  • ViewController中不要引入Model,引入了就難免會在Controller中對Model做處理;
  • 對於很簡單的介面使用MVVM會增加程式碼量,但如果介面中內容很多、Cell樣式也很多的情況下使用MVVM可以很好地將VC中處理Cell相關的工作分離出來。