viewModel作为连接view与model之间的桥梁 , view与model互不相通!
在控制器中先通过model与viewModel互相绑定好 , 然后将绑定好了model的viewMode对象再去跟view进行绑定!
从而使viewModel达成了view和model之间
桥梁的作用!~
MVVMViewCtrl.h
#import <UIKit/UIKit.h>
@interface MVVMViewCtrl : UIViewController
@end
MVVMViewCtrl.m
// MVVM --> model view viewModel 三个文件
#import "MVVMViewCtrl.h"
#import "MVVMPaper.h" // model
#import "MVVMView.h" // view
#import "MVVMViewModel.h" // viewModel
@interface MVVMViewCtrl ()
@property (nonatomic, strong) MVVMPaper *paper;
@property (nonatomic, strong) MVVMView *mvvmView;
@property (nonatomic, strong) MVVMViewModel *viewModel;
@end
@implementation MVVMViewCtrl
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor lightGrayColor];
// mvvmView:
self.mvvmView.frame = self.view.bounds;
[self.view addSubview:self.mvvmView];
// view --> viewModel --> model
// view <-- viewModel <-- model
// 双向绑定:
// 控制器的代码非常简单 , view的布局 , viewModel 与 model 的定制 , view 与 viewModel 之间的定制:
// 保证view与model彼此之间不互通~
// mvvmModel:
// 给一个初始值"line 0".
self.paper.contents = @"line 0";
// mvvmViewModel:
// 所以这里应该先赋值模型 , 让viewModel与model进行绑定:
[self.viewModel setWithModel:self.paper];
// 然后再让view与viewModel进行绑定 , 此时的 viewModel 已经是 与model 进行绑定完成之后的viewModel了!
[self.mvvmView setWithViewModel:self.viewModel];
}
#pragma mark - getter方法
- (MVVMPaper *)paper
{
if(!_paper)
{
_paper = [[MVVMPaper alloc] init];
}
return _paper;
}
- (MVVMView *)mvvmView
{
if(!_mvvmView)
{
_mvvmView = [[MVVMView alloc] init];
}
return _mvvmView;
}
- (MVVMViewModel *)viewModel
{
if(!_viewModel)
{
_viewModel = [[MVVMViewModel alloc] init];
}
return _viewModel;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
@end
MVVMView.h
#import <UIKit/UIKit.h>
// view里添加了viewModel:
#import "MVVMViewModel.h"
@interface MVVMView : UIView
// view监听viewModel中的contentString属性:
- (void)setWithViewModel:(MVVMViewModel *)viewModel;
@end
MVVMView.m
#import "MVVMView.h"
#import "FBKVOController.h"
#import "NSObject+FBKVOController.h"
@interface MVVMView ()
@property (nonatomic, strong) UILabel *contentsLabel;
@property (nonatomic, strong) UIButton *button;
@property (nonatomic, strong) MVVMViewModel *viewModel;
@end
@implementation MVVMView
- (instancetype)init
{
self = [super init];
if (self)
{
[self addSubview:self.contentsLabel];
[self addSubview:self.button];
}
return self;
}
// 这里是 view 与 viewModel 进行动态绑定的过程 , 让视图作为属性的监听器监听viewModel中的 contentString 属性 , 一旦 contentString 的值有改变 , 就会触发回调 , 这里的block回调中的 change 参数就会有新值 , 把新值赋值给视图中 label 的 text 属性:
- (void)setWithViewModel:(MVVMViewModel *)viewModel
{
// 要一个 初始值 和 改变之后的 新值:
[self.KVOController observe:viewModel
keyPath:@"contentString"
options: NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew
block:^(id _Nullable observer,
id _Nonnull object,
NSDictionary<NSKeyValueChangeKey , id> * _Nonnull change)
{
self.contentsLabel.text = change[NSKeyValueChangeNewKey];
}];
// 这里再把赋值过来的viewModel实参传递给实例变量 , 用来作为传递点击事件的参数
self.viewModel = viewModel;
}
#pragma mark - 按钮的点击事件
- (void)buttonClicked:(UIButton *)button
{
// 把所有的业务逻辑相关代码都传递到viewModel中:
[self.viewModel onPrintClick];
}
- (MVVMViewModel *)viewModel
{
if(!_viewModel)
{
_viewModel = [[MVVMViewModel alloc] init];
}
return _viewModel;
}
- (UIButton *)button
{
if(!_button)
{
_button = [UIButton buttonWithType:UIButtonTypeCustom];
[_button setTitle:@"print" forState:UIControlStateNormal];
[_button setFrame:CGRectMake(0, 200, 100, 100)];
_button.layer.cornerRadius = 5;
_button.layer.masksToBounds = YES;
_button.backgroundColor = [UIColor redColor];
[_button setTitleColor:[UIColor blackColor] forState:UIControlStateNormal];
_button.backgroundColor = [UIColor redColor];
[_button addTarget:self action:@selector(buttonClicked:) forControlEvents:UIControlEventTouchUpInside];
}
return _button;
}
- (UILabel *)contentsLabel
{
if(!_contentsLabel)
{
_contentsLabel = [[UILabel alloc] init];
_contentsLabel.frame = CGRectMake(100, 100, 100, 30);
_contentsLabel.font = [UIFont systemFontOfSize:20.0f];
_contentsLabel.textColor = [UIColor blackColor];
}
return _contentsLabel;
}
@end
MVVMViewModel.h
#import <Foundation/Foundation.h>
// viewModel是中间的桥梁 , 它连接着view与model , view和model彼此之间是不互通的!
// viewModel中印入model:
#import "MVVMPaper.h"
@interface MVVMViewModel : NSObject
@property (nonatomic, copy) NSString *contentString;
// 设置模型:
- (void)setWithModel:(MVVMPaper *)paper;
// view传递过来的点击事件:
- (void)onPrintClick;
@end
MVVMViewModel.m
#import "MVVMViewModel.h"
#import "FBKVOController.h"
@interface MVVMViewModel ()
@property (nonatomic, strong) MVVMPaper *paper;
@end
@implementation MVVMViewModel
// MVVM的核心: 通过 KVO 的方法将viewModel与view进行 "绑定";
// 绑定的方法通过Facebook开源库 FBKVO
- (instancetype)init
{
self = [super init];
if (self)
{
self.paper = [[MVVMPaper alloc] init];
}
return self;
}
// 传递模型实参给模型属性: , 让模型里的contents字段赋值给viewModel中的 contentString 字段 , 这里就完成了属性之间的关联:
// 让模型与viewModel一一关联 , 之后的视图与model之间的关联都变成了视图与viewModel之间的关联了!
- (void)setWithModel:(MVVMPaper *)paper
{
self.paper = paper;
self.contentString = paper.contents;
}
// 点击事件的回调:
- (void)onPrintClick
{
int randomColor = arc4random() % 10;
self.paper.contents = [NSString stringWithFormat:@"line %d" , (randomColor + 1)];
// 这里 contentString 字段改变了 , viewModel中的监听器就会监听到这里的改变 , 从而通过contentString 获取的新值赋值给view的label的text属性:
self.contentString = self.paper.contents;
}
@end
MVVMPaper.h
// MVVM中的 model 模型文件:
#import <Foundation/Foundation.h>
@interface MVVMPaper : NSObject
@property (nonatomic, copy) NSString *contents;
@end
MVVMPaper.m
#import "MVVMPaper.h"
@implementation MVVMPaper
@end
网友评论