美文网首页
MVVM模式示例代码

MVVM模式示例代码

作者: 小苗晓雪 | 来源:发表于2018-08-27 09:44 被阅读168次
    文件示例图

    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
    

    愿编程让这个世界更美好

    相关文章

      网友评论

          本文标题:MVVM模式示例代码

          本文链接:https://www.haomeiwen.com/subject/fehziftx.html