介绍
MVVM模式将Presenter改名为ViewModel,基本上与MVP模式完全一致。
唯一的区别是,它采用双向绑定(data-binding) : View<->ViewModel, ViewModel作为Model中值的映射,是数据发生改变时,通知View中发生改变,以后不需要考虑View和Model之间的交互更新,只需着手界面布局逻辑即可。
- View和Model 不直接关联,而是通过ViewModel作为枢纽,沟通View和Model之间的关系。
- View中控件的值与ViewModel属性进行绑定,通过KVO键值观察(这样当model的值发生变化时,View会自动发生改变)
View和Model通过ViewModel实现动态关联。
代码
Model
//.h
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Model : NSObject
@property(nonatomic,copy)NSString *name;
@end
NS_ASSUME_NONNULL_END
//.m
#import "Model.h"
@implementation Model
@end
ViewModel
//.h
#import <Foundation/Foundation.h>
#import "Model.h"
NS_ASSUME_NONNULL_BEGIN
@interface ViewModel : NSObject
@property(nonatomic,copy)NSString *nameStr;
@property(nonatomic,strong)Model *model;
-(void)setWithModel:(Model *)model;
-(void)clickChangeName;
@end
NS_ASSUME_NONNULL_END
//.m
#import "ViewModel.h"
@implementation ViewModel
-(instancetype)init{
if (self = [super init]) {
}
return self;
}
-(void)setWithModel:(Model *)model{
self.model = model;
self.nameStr = model.name;
}
-(void)clickChangeName{
self.model.name = [NSString stringWithFormat:@"name%d",arc4random()%10];
self.nameStr = self.model.name;
NSLog(@"%@",self.nameStr);
}
@end
View
//.h
#import <UIKit/UIKit.h>
#import "ViewModel.h"
NS_ASSUME_NONNULL_BEGIN
@interface View : UIView
-(void)setWithViewModel:(ViewModel *)vm;
@end
NS_ASSUME_NONNULL_END
//.m
#import "View.h"
@interface View ()
@property(nonatomic,strong)ViewModel *vm;
@property(nonatomic,strong)UILabel *label;
@property(nonatomic,strong)UIButton *button;
@end
@implementation View
- (instancetype)init {
self = [super init];
if (self) {
self.backgroundColor = [UIColor whiteColor];
self.frame = [UIScreen mainScreen].bounds;
self.label = [[UILabel alloc]initWithFrame:CGRectMake(150,100 , 100, 30)];
self.label.backgroundColor = [UIColor orangeColor];
[self addSubview:_label];
self.button = [UIButton new];
_button.backgroundColor = [UIColor redColor];
[_button setTitle:@"点击" forState:UIControlStateNormal];
[_button addTarget:self action:@selector(mvvmClickChangModel) forControlEvents:UIControlEventTouchUpInside];
_button.frame = CGRectMake(150, 200, 50, 50);
[self addSubview:_button];
}
return self;
}
- (void)setWithViewModel:(ViewModel *)vm {
self.vm = vm;
//KVO
[self.vm addObserver:self forKeyPath:@"nameStr" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
self.label.text = vm.nameStr;
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change: (NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"nameStr"]&&[change objectForKey:NSKeyValueChangeNewKey]) {
NSNumber *new = [change objectForKey:NSKeyValueChangeNewKey];
self.label.text = [NSString stringWithFormat:@"%@",new];
}
}
-(void)mvvmClickChangModel{
[self.vm clickChangeName];
}
-(void)dealloc{
[self.vm removeObserver:self forKeyPath:@"nameStr"];
}
@end
ViewController
//.m
#import "ViewController.h"
#import "View.h"
#import "Model.h"
#import "ViewModel.h"
@interface ViewController ()
@property (nonatomic, strong) ViewModel * viewModel;
@property (nonatomic, strong) View *pView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.pView = [View new];
Model *model = [Model new];
model.name = @"name1";
ViewModel *viewModel = [ViewModel new];
[self.view addSubview:self.pView];
//*viewModel 作为枢纽 沟通view和model之间关系
[viewModel setWithModel:model];
[self.pView setWithViewModel:viewModel];
}
@end
参考MVVM