美文网首页
用MVVM模式和ReactiveCocoa(RAC)绑定写一个D

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

作者: a浮生若梦a | 来源:发表于2019-08-01 10:58 被阅读0次

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

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

RAC

/在LoginView里:/

  • 1.用RAC把输入账号和输入密码的TextField和ViewModel的属性(accountStr,passwordStr)进行绑定。(实时监测信号变化)

  • 2.用RAC监听(iconUrlStr)根据输入不同账号内容来显示不同头像。(输入内容只有 0, 012, 0123, 01234 这四种图片对应)

  • 3.用RAC监听登录按钮可编辑状态。 按钮可点击事件。(事件响应,RACCommand只需执行 - (RACSignal *)execute:(id)input 方法就可以开始并执行)\n\n4.用RAC监听菊花加载显示。(skip:1 方法是跳过第一步的意思)

/在LoginViewModel里面:/

  • 1.VM里面头像图片的属性(iconUrlStr)和输入账号的TextField的输入框进行映射绑定。(功能:对图片URL进行处理)

  • 2.VM里检测属性(accountStr,passwordStr),用来判断登录按钮是否可以高亮或点击。

  • 3.VM里面属性(loginStatusSubject)用来检测登录的状态。

  • 4.RACCommand用来实现请求的响应,具体请查看代码。

/Login整理功能:/

  • 1.输入框,输入 0, 012, 0123, 01234 这四种数字头像一一对应。

  • 2.账号密码判断,必须都为01234,才可以登录成功。

  • 3.俩个输入框必须都有输入才可以点击登录按钮。

  • 4.登录中显示登录状态。菊花加载显/隐。

/个人信息页面也是通过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中:
  • 获取到Model数据之后,把Model的数据和ViewModel的数据绑定到一起,就是说model的属性值改变后,ViewModel属性值也跟随改变。

  • (利用runtime获取属性,利用RAC检测aModel的属性变化)

  • 把按钮点击事件逻辑实现到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中:
  • 获取到ViewModel数据之后,把ViewModel的数据和View的数据绑定到一起,就是说ViewModel的属性值改变后,View属性值也跟随改变。

  • (利用runtime获取属性,利用RAC检测ViewModel的属性变化)

  • 把按钮点击事件逻辑实现到ViewModel来实现。

代码如下:

#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地址

相关文章

网友评论

      本文标题:用MVVM模式和ReactiveCocoa(RAC)绑定写一个D

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