最近看到新浪微博上以及iOS開發的論壇里面談到MVVM設計模式,所謂MVVM就是Model-View-ViewModel的縮寫,關於MVVM的概念,這里我不想過多的介紹,有很多介紹的很詳細的博文,這里我們直奔主題,談一談MVVM如何利用到項目中去。
首先我們在建立項目中的時候可分為如下模塊,Model,View,ViewModel,Controller.
Model: 數據模型,用來處理數據
View: 視圖類,用來做界面設計
ViewModel: 用來寫界面以及邏輯
Controller: 控制器類,用來處理控制器之間的邏輯
這里有人肯定會問了,MVVM不是Model-View-ViewModel嗎,為什么還會有控制器,這里的控制器是用來為頁面跳轉以及加載提供入口的,以及將控制器邏輯利用代理和代碼塊的方式讓ViewModel來實現。光說不練假把式,先來看一看文件夾吧。

和我前面說的一樣,模塊被分為了4部分,這樣我們可以使我們的controller不再那么(胖),與傳統的MVC相比,文件反而多了,可是這樣一來,控制器里面的代碼就減少了很多,只需要調用對應的功能的函數就可以了。接下來再看看viewModel里面寫的什么
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> #import "WeatherView.h" #import "weatherModel.h" @interface WeatherViewModel : NSObject @property (nonatomic, strong) WeatherView *view; /**< 用來與controller里面的View匹配*/ @property (nonatomic, strong) weatherModel *model; @property (nonatomic, strong) UITableView *myTableView; - (instancetype)initWithFrame:(CGRect)frame;
- (void)didSelect; @end
#import "WeatherViewModel.h" #import "WeatherTableViewCell.h" #import "weatherModel+Request.h" static NSString * const kApiUrl = @"www.baidu.com"; @implementation WeatherViewModel - (instancetype)initWithFrame:(CGRect)frame { self = [super init]; if (self) { [self initWithModel]; _view = [[WeatherView alloc]initWithFrame:frame]; [_view addSubview:self.myTableView]; } return self; } - (void)initWithModel { [weatherModel requestWithURL:kApiUrl AndParmars:@{} WithSuccessBlock:^(id responseObject) { self.model = responseObject[@"data"]; } WithFailBlock:^(id error) { }]; } - (UITableView *)myTableView { if (!_myTableView) { _myTableView = [[UITableView alloc]initWithFrame:_view.frame style:UITableViewStylePlain]; _myTableView.tableFooterView = [[UIView alloc]init]; _myTableView.backgroundColor = [UIColor yellowColor]; } return _myTableView; }
- (void)didSelect {
NSLog(@"點擊了cell");
}
這里我直接把UI也寫了進來,到了這里各位可能要問了,不是說是viewModel嗎,而且這個類是繼承NSObject的,為什么要在這里面寫UI。沒錯,在我看來它也只是一個工具類,可我的目的是想讓controller變得更簡,簡到我們看一個controller的時候只需要知道它有哪些功能,能做什么就好。其他的全部交給viewmodel去處理吧。我們可以把網絡請求還有一些邏輯處理全都放進來,極大的降低代碼的耦合度。
接下來我們再來看看controller里面寫什么,
#import "WeatherViewController.h" #import "WeatherViewModel.h" #import "WeatherTableViewCell.h" @interface WeatherViewController ()<UITableViewDataSource,UITableViewDelegate> { WeatherViewModel *viewModel; /**< 當前控制器的viewModel*/ } @end @implementation WeatherViewController - (void)viewDidLoad { [super viewDidLoad]; [self setUp]; // Do any additional setup after loading the view. } - (void)setUp { self.title = @"天氣測試"; viewModel = [[WeatherViewModel alloc] initWithFrame:self.view.bounds]; viewModel.myTableView.delegate = self; viewModel.myTableView.dataSource = self; [self.view addSubview:viewModel.view]; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return 20; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *reuseIdentifier = @"reuseIdentifier"; WeatherTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:reuseIdentifier]; if (!cell) { cell = [[WeatherTableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; cell.textLabel.text = @"it is a test"; } return cell; } - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { [viewModel didSelect]; }
controller里面不需要寫UI,直接把viewModel里面所定義的view加在當前控制器上view上就可以了。實現一些必要的代理,這里大伙兒一定會想,為什么UI都寫在了viewmodel里,還要把代理方法寫在controller里,這里我嘗試了在viewmodel里面寫,但是會存在cell的復用問題。如果您有好的解決方法,請您給我留言,非常感謝。
關於如何將控制器的邏輯交給viewmodel,可以有代理,block,或者通知,當然,目前最完美的當屬'ReactiveCocoa了,有關reactiveCocoa框架的介紹也有很多,這里有一篇比較好的文章 http://nathanli.cn/2015/08/27/reactivecocoa2-%E6%BA%90%E7%A0%81%E6%B5%85%E6%9E%90/。
以上是關於MVVM的一些個人理解,理解的過程當中肯定存在有些不足,希望在以后的使用過程當中能有更好的總結。
