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相關的工作分離出來。