用MVVM模式和ReactiveCocoa(RAC)绑定写一个D

2019-08-01  本文已影响0人  a浮生若梦a

下面是用RAC做的另一个小例子

简单功能介绍,RAC+MVVM-Demo地址

RAC

/在LoginView里:/

/在LoginViewModel里面:/

/Login整理功能:/

/个人信息页面也是通过RAC绑定,监听属性实现,具体详看代码/

RAC+MVVM-Demo地址


1. 函数式响应式编程

2. 流程: 信号产生-->信号订阅-->信号发送-->信号销毁

2. RAC-->KVO,通知,点击手势,按钮的点击事件绑定等

3. TextField属性监听等,Array,Dictionary,遍历等。

4. Map映射对输入的内容进行处理,过滤后再发送信号。

5. Combine 对组合的信号进行绑定。

6. OC语言库 pod 导入是 ReactiveObjC->3.1.0 

7. Swift语言库  pod 导入是 ReactiveSwift->4.0.0 

8. 还有好多功能等等。

MVVM

MVVM.png

MVVM+RAC网络上有好多这里不再阐述。
MVVM重要的部分是引入了视图模型,并且视图通过某种观察者从视图模型获取更新。

这里附上MVVM-Demo地址

直接说项目,如图所示:


MVVM.png
在viewController中的关系如下
#import "CBViewController.h"
#import "CBView.h"
#import "CBViewModel.h"

@interface CBViewController ()

@property (nonatomic,strong) CBViewModel *aViewModel;
@property (nonatomic,strong) CBView *aView;
@end

@implementation CBViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.navigationItem.title = @"MVVM练习";
    self.view.backgroundColor = [UIColor whiteColor];
    
    // creat viewModel
    _aViewModel = [[CBViewModel alloc] init];
    
    
    // creat view
    _aView = [[CBView alloc] initWithFrame:self.view.bounds];
    [self.view addSubview:_aView];
    
    
    // viewModel get data (example requests the data)
    //这里模拟请求数据,获取数据
    [self.aViewModel getModelData];
    
    // give the data to the view
   // 把获取到的数据,更新到view视图上
    [self.aView showView:_aViewModel];
}

@end
在ViewModel中:

代码如下:

#import "CBViewModel.h"
#import "CBModel.h"

@interface CBViewModel ()

@property (nonatomic,strong) CBModel *aModel;
@end

@implementation CBViewModel

- (void)getModelData {
    _aModel = [[CBModel alloc] init];
    _aModel.titleStr = @"个人信息提交";
    _aModel.nameStr = @"张小豪";
    _aModel.sexStr = @"男";
    _aModel.ageStr = @"19";
    _aModel.successStr = @"1";

    //利用runtime获取属性,把model的属性和ViewModel的属性绑定到一起
    unsigned int aCount = 0;
    objc_property_t *aProperties = class_copyPropertyList([self.aModel class], &aCount);
    for (int i=0; i<aCount; i++) {
        objc_property_t aProperty = aProperties[i];
        const char *aName = property_getName(aProperty);
        NSString *nameStr = [NSString stringWithUTF8String:aName];
        
        if ([nameStr isEqualToString:@"titleStr"]
            || [nameStr isEqualToString:@"nameStr"]
            || [nameStr isEqualToString:@"sexStr"]
            || [nameStr isEqualToString:@"ageStr"]
            || [nameStr isEqualToString:@"successStr"] ) {
            
            // 利用RAC检测aModel的属性变化
            @weakify(self);
            [[self.aModel rac_valuesAndChangesForKeyPath:nameStr options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) observer:nil] subscribeNext:^(RACTuple * _Nullable x) {
                @strongify(self);
                if ([nameStr isEqualToString:@"titleStr"]) {
                    self.aTitle = x.first?:@"";
                }else if ([nameStr isEqualToString:@"nameStr"]) {
                    self.aName = x.first?:@"";
                }else if ([nameStr isEqualToString:@"sexStr"]) {
                    self.aSex = x.first?:@"";
                }else if ([nameStr isEqualToString:@"ageStr"]) {
                    self.aAge = x.first?:@"";
                }else if ([nameStr isEqualToString:@"successStr"]) {
                    self.aSuccess = x.first?:@"";
                }
            }];
        }
    }
}

- (void)viewModelBtnClickedAction {
    if ([self.aModel.successStr isEqualToString:@"1"]) {
        self.aModel.titleStr = @"信息错误";
        self.aModel.nameStr = @"xxx";
        self.aModel.sexStr = @"xxx";
        self.aModel.ageStr = @"xxx";
        self.aModel.successStr = @"xxx";
    }else {
        self.aModel.titleStr = @"个人信息提交";
        self.aModel.nameStr = @"张小豪";
        self.aModel.sexStr = @"男";
        self.aModel.ageStr = @"19";
        self.aModel.successStr = @"1";
    }
}

@end
在View中:

代码如下:

#import "CBView.h"

@implementation CBView

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        self.backgroundColor = [UIColor orangeColor];
        [self viewLayout];
    }
    return self;
}

- (void)viewLayout {
    CGSize mainSize = self.frame.size;
    _titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(12, 80, mainSize.width-12*2, 30)];
    _titleLabel.font = [UIFont boldSystemFontOfSize:16.0];
    _titleLabel.textAlignment = NSTextAlignmentCenter;
    _titleLabel.textColor = [UIColor whiteColor];
    [self addSubview:_titleLabel];
    
    _nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(12, CGRectGetMaxY(_titleLabel.frame)+30, 100, 30)];
    _nameLabel.font = [UIFont systemFontOfSize:16.0];
    _nameLabel.textColor = [UIColor whiteColor];
    [self addSubview:_nameLabel];
    
    _sexLabel = [[UILabel alloc] initWithFrame:CGRectMake(12, CGRectGetMaxY(_nameLabel.frame)+30, 100, 30)];
    _sexLabel.backgroundColor = [UIColor lightGrayColor];
    _sexLabel.font = [UIFont systemFontOfSize:16.0];
    _sexLabel.textColor = [UIColor whiteColor];
    [self addSubview:_sexLabel];
    
    _ageLabel = [[UILabel alloc] initWithFrame:CGRectMake(12, CGRectGetMaxY(_sexLabel.frame)+30, 100, 30)];
    _ageLabel.backgroundColor = [UIColor lightGrayColor];
    _ageLabel.font = [UIFont systemFontOfSize:16.0];
    _ageLabel.textColor = [UIColor whiteColor];
    [self addSubview:_ageLabel];
    
    _sureBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    _sureBtn.frame = CGRectMake(20, CGRectGetMaxY(_ageLabel.frame)+30, mainSize.width-20*2, 40);
    [_sureBtn setTitle:@"-点我刷新数据-" forState:UIControlStateNormal];
    [_sureBtn addTarget:self action:@selector(onPrintClick:) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:_sureBtn];
    
    _successLabel = [[UILabel alloc] initWithFrame:CGRectMake(30, CGRectGetMaxY(_sureBtn.frame)+50, mainSize.width-30*2, 40)];
    _successLabel.font = [UIFont boldSystemFontOfSize:16.0];
    _successLabel.textAlignment = NSTextAlignmentCenter;
    _successLabel.textColor = [UIColor blueColor];
    [self addSubview:_successLabel];
}

- (void)onPrintClick:(UIButton *)sender {
    [self.aViemModel viewModelBtnClickedAction];
}

- (void)showView:(CBViewModel *)viewModel {
    self.aViemModel = viewModel;
    
    //利用runtime获取属性,把ViewModel的属性和view视图的属性绑定到一起。
    unsigned int aCount = 0;
    objc_property_t *aProperties = class_copyPropertyList([viewModel class], &aCount);
    for (int i=0; i<aCount; i++) {
        objc_property_t aProperty = aProperties[i];
        const char *aName = property_getName(aProperty);
        NSString *nameStr = [NSString stringWithUTF8String:aName];
        
        if ([nameStr isEqualToString:@"aTitle"]
            || [nameStr isEqualToString:@"aName"]
            || [nameStr isEqualToString:@"aSex"]
            || [nameStr isEqualToString:@"aAge"]
            || [nameStr isEqualToString:@"aSuccess"] ) {
            
            // 利用RAC检测viewModel的属性变化
            @weakify(self);
            [[viewModel rac_valuesAndChangesForKeyPath:nameStr options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) observer:nil] subscribeNext:^(RACTuple * _Nullable x) {
                @strongify(self);
                if ([nameStr isEqualToString:@"aTitle"]) {
                    self.titleLabel.text = x.first?:@"";
                }else if ([nameStr isEqualToString:@"aName"]) {
                    self.nameLabel.text = x.first?:@"";
                }else if ([nameStr isEqualToString:@"aSex"]) {
                    self.sexLabel.text = x.first?:@"";
                }else if ([nameStr isEqualToString:@"aAge"]) {
                    self.ageLabel.text = x.first?:@"";
                }else if ([nameStr isEqualToString:@"aSuccess"]) {
                    self.successLabel.text = x.first?:@"";
                }
            }];
        }
    }
}
@end

model里面就是定义一些数据,到这里就完成model和viewModel的数据互通,然后viewModel和View之间互通。

这里附上MVVM-Demo地址

上一篇 下一篇

猜你喜欢

热点阅读