iOS MVVM模式總結
MVVM模式中,ViewModel的作用是加工原來MVC模式中Controller或者Model中的根據業務場景要處理的資料,即根據業務場景處理加工Model資料,然後返回給Controller,相當於一箇中間轉化層,ViewModel的資料結構與Model的資料結構比較相似,因為是Model根據業務場景的一個轉化。是處理需要展示的資料(包括根據業務需要處理的資料,還有比如網路請求資料,比如資料轉換等等),然後將加工得到的資料給ViewController。因此ViewModel一般要引入Model的標頭檔案,在ViewModel裡面進行邏輯加工和資料處理的結果返回給ViewController。所以,ViewController裡面也要引入ViewModel
Model不再像MVC那樣直接與ViewController打交道,而是與ViewModel打交道,ViewModel通過Block或者屬性將處理Model的結果返回給ViewController。
讓我們看一個簡單的 Person Model 以及相應的 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
Cool!現在我們假設我們有一個 PersonViewController ,在 viewDidLoad 裡,只需要基於它的 model 屬性設定一些 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];
}
這全都直截了當,標準的 MVC。現在來看看我們如何用一個 View Model 來增強它。
@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 的實現大概如下:
@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
Cool!我們已經將 viewDidLoad 中的表示邏輯放入我們的 View Model 裡了。此時,我們新的 viewDidLoad 就會非常輕量:
- (void)viewDidLoad {
[super viewDidLoad];
self.nameLabel.text = self.viewModel.nameText;
self.birthdateLabel.text = self.viewModel.birthdateText;
}
所以,如你所見,並沒有對我們的 MVC 架構做太多改變。還是同樣的程式碼,只不過移動了位置。它與 MVC 相容,帶來更輕量的 View Controllers。