緒論
以前在項(xiàng)目中大家都很喜歡使用的MVC模式,MVC即Model-VIew-Controller。他是1970年代被引入到軟件設(shè)計(jì)大眾的。MVC模式致力于關(guān)注點(diǎn)的切分,這意味著model和controller的邏輯是不與用戶界面(View)掛鉤的。因此,維護(hù)和測試程序變得更加簡單容易。
MVC
MVC設(shè)計(jì)模式將應(yīng)用程序分離為3個(gè)主要的方面:Model,View和Controller。

- Model
Model代表了描述業(yè)務(wù)路邏輯,業(yè)務(wù)模型、數(shù)據(jù)操作、數(shù)據(jù)模型的一系列類的集合。這層也定義了數(shù)據(jù)修改和操作的業(yè)務(wù)規(guī)則。- View
View代表了UI組件,像CSS,jQuery,html等。他只負(fù)責(zé)展示從controller接收到的數(shù)據(jù)。也就是把model轉(zhuǎn)化成UI。- Controller
Controll負(fù)責(zé)處理流入的請求。它通過View來接受用戶的輸入,之后利用Model來處理用戶的數(shù)據(jù),最后把結(jié)果返回給View。Controll就是View和Model之間的一個(gè)協(xié)調(diào)者。
MVVM:
MVVM是MVC思想的完全變革。它是將“數(shù)據(jù)模型數(shù)據(jù)雙向綁定”的思想作為核心,因此在View和Model之間沒有聯(lián)系,通過ViewModel進(jìn)行交互,而且Model和ViewModel之間的交互是雙向的,因此視圖的數(shù)據(jù)的變化會同時(shí)修改數(shù)據(jù)源,而數(shù)據(jù)源數(shù)據(jù)的變化也會立即反應(yīng)到View上。

- 用戶和View交互。
- View和ViewModel是多對一關(guān)系。意味著一個(gè)ViewModel只映射多個(gè)View。
- View持有ViewModel的引用,但是ViewModel沒有任何View的信息。
- View 和ViewModel之間有雙向數(shù)據(jù)綁定關(guān)系。
為什么使用MVVM
在 iOS 上使用 MVVM 的動(dòng)機(jī),就是它能減少 View Controller 的復(fù)雜性并使得表示邏輯更易于測試。通過一些例子,我們將看到它如何達(dá)到這些目標(biāo)。
- MVVM 可以兼容你當(dāng)下使用的 MVC 架構(gòu)。
- MVVM 增加你的應(yīng)用的可測試性。
- MVVM 配合一個(gè)綁定機(jī)制效果最好。
注:MVVM 基本上就是 MVC 的改進(jìn)版,所以很容易就能看到它如何被整合到現(xiàn)有使用典型 MVC 架構(gòu)的應(yīng)用中。讓我們看一個(gè)簡單的 Person Model 以及相應(yīng)的 View Controller:
@interface Person : NSObject
- (instancetype)initwithSalutation:(NSString *)salutation firstName:(NSString *)firstName lastName:(NSString *)lastName birthdate:(NSDate *)birthdate;
@property (nonatomic, readonly) NSString *salutation;
@property (nonatomic, readonly) NSString *firstName;
@property (nonatomic, readonly) NSString *lastName;
@property (nonatomic, readonly) NSDate *birthdate;
@end
接著我們?nèi)?chuàng)建一個(gè)PersonViewController ,在 viewDidLoad 里,只需要基于它的 model 屬性設(shè)置一些 Label 即可。
- (void)viewDidLoad {
[super viewDidLoad];
if (self.model.salutation.length > 0) {
self.nameLabel.text = [NSString stringWithFormat:@"%@ %@ %@", self.model.salutation, self.model.firstName, self.model.lastName];
} else {
self.nameLabel.text = [NSString stringWithFormat:@"%@ %@", self.model.firstName, self.model.lastName];
}
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"EEEE MMMM d, yyyy"];
self.birthdateLabel.text = [dateFormatter stringFromDate:model.birthdate];
}
以上就是標(biāo)準(zhǔn)的 MVC?,F(xiàn)在來看看我們?nèi)绾斡靡粋€(gè) View Model 來增強(qiáng)它。首先創(chuàng)建一個(gè)PersonViewModel。
@interface PersonViewModel : NSObject
- (instancetype)initWithPerson:(Person *)person;
@property (nonatomic, readonly) Person *person;
@property (nonatomic, readonly) NSString *nameText;
@property (nonatomic, readonly) NSString *birthdateText;
@end
View Model 的具體實(shí)現(xiàn)大概如下:
@implementation PersonViewModel
- (instancetype)initWithPerson:(Person *)person {
self = [super init];
if (!self)
return nil;
_person = person;
if (person.salutation.length > 0) {
_nameText = [NSString stringWithFormat:@"%@ %@ %@", self.person.salutation, self.person.firstName, self.person.lastName];
} else {
_nameText = [NSString stringWithFormat:@"%@ %@", self.person.firstName, self.person.lastName];
}
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"EEEE MMMM d, yyyy"];
_birthdateText = [dateFormatter stringFromDate:person.birthdate];
return self;
}
@end
此時(shí)的我們已經(jīng)將 viewDidLoad 中的表示邏輯放入我們的 View Model 里了。此時(shí),我們新的 viewDidLoad 就會非常輕量:
- (void)viewDidLoad {
[super viewDidLoad];
self.nameLabel.text = self.viewModel.nameText;
self.birthdateLabel.text = self.viewModel.birthdateText;
}
因此,MVVM并沒有對我們的 MVC 架構(gòu)做太多改變。還是同樣的代碼,只不過移動(dòng)了位置。它與 MVC 兼容,帶來更輕量的 View Controllers。