MVVM

256 阅读2分钟

介绍

MVVM模式将Presenter改名为ViewModel,基本上与MVP模式完全一致。

唯一的区别是,它采用双向绑定(data-binding) : View<->ViewModel, ViewModel作为Model中值的映射,是数据发生改变时,通知View中发生改变,以后不需要考虑View和Model之间的交互更新,只需着手界面布局逻辑即可。

  1. View和Model 不直接关联,而是通过ViewModel作为枢纽,沟通View和Model之间的关系。
  2. 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