美文网首页
IOS RAC实践

IOS RAC实践

作者: Devil_Chen | 来源:发表于2019-01-16 13:56 被阅读0次

前言

开始,要快

一、创建视图

image.png

二、ViewController中绑定视图和ViewModel

  • 定义界面的控件
@interface ViewController ()

@property (weak, nonatomic) IBOutlet UILabel *statuslabel;
@property (weak, nonatomic) IBOutlet UIImageView *iconImageView;
@property (weak, nonatomic) IBOutlet UITextField *accountTF;
@property (weak, nonatomic) IBOutlet UITextField *passwordTF;
@property (weak, nonatomic) IBOutlet UIButton *loginButton;

@property (nonatomic, strong) LoginViewModel *loginVM;

@end

  • 绑定视图和ViewModel
    @weakify(self);
    //UI实时修改的值 传递给 --> vm
    RAC(self.loginVM,account) = self.accountTF.rac_textSignal;
    RAC(self.loginVM,password) = self.passwordTF.rac_textSignal;
    // 按钮是否可点击
    RAC(self.loginButton,enabled) = self.loginVM.loginEnableSignal;
    // 响应的发送 -- 响应的接受 --- vm -- > UI (根据VM改变的值改变UI状态标签的值)
    RAC(self.statuslabel,text) = self.loginVM.statusSubject;
    [RACObserve(self.statuslabel, text) subscribeNext:^(id  _Nullable x) {
        if ([x isEqualToString:@"正在登录"]) {
            [SVProgressHUD showWithStatus:x];
        }else{
            [SVProgressHUD dismiss];
        }
    }];
    //监听loginVM中的iconUrl值变化改变UI的图片Icon
    [RACObserve(self.loginVM, iconUrl) subscribeNext:^(id  _Nullable x) {
        @strongify(self);
        self.iconImageView.image = [UIImage imageNamed:x];
    }];
    // vm ---> signal
    [self.loginVM.loginEnableSignal subscribeNext:^(NSNumber *x) {
        @strongify(self);
        UIColor *color = (x.intValue == 0) ? [UIColor lightGrayColor] : [UIColor blueColor];
        [self.loginButton setBackgroundColor:color];
    }];
    //监听按钮点击事件
    [[self.loginButton rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(__kindof UIControl * _Nullable x) {
        // ----> vm  ---> 迁移
        // 涉及 ---> 网络 ---> 状态 -- 响应 ---- 命令 ---vm ---> 请求网络
        //loginCommand开始执行
        [self.loginVM.loginCommand execute:@"开始登录"];
    }];

三、ViewModel中处理获取的数据及根据业务逻辑创建不同信号

  • 定义变量及信号
@interface LoginViewModel : NSObject

@property (nonatomic, copy) NSString *iconUrl;
@property (nonatomic, copy) NSString *account;
@property (nonatomic, copy) NSString *password;
@property (nonatomic, strong) RACSignal  *loginEnableSignal;
@property (nonatomic, strong) RACCommand *loginCommand;
@property (nonatomic, strong) RACSubject *statusSubject;
@property (nonatomic) BOOL islogining;


@property (nonatomic,strong) LoginM *loginM;

@end
  • 监听变量变化
- (instancetype)init{
    if (self = [super init]) {
        
        // 绑定iconUrl的值由account的值改变而改变
        RAC(self,iconUrl) = [[[RACObserve(self, account) skip:1] map:^id _Nullable(id  _Nullable value) {
            return [NSString stringWithFormat:@"www:%@",value];
        }] distinctUntilChanged];
        
        // 创建按钮是否能点击信号 --- account + password(都有值的话可以点击)  --- 函数 组合+聚合
        self.loginEnableSignal = [RACSignal combineLatest:@[RACObserve(self, account),RACObserve(self, password)] reduce:^id (NSString *account,NSString *password){
            return @(account.length>0&&password.length>0);
        }];

        self.islogining = NO;
        self.statusSubject = [RACSubject subject];
        [self setupLoginCommand];
    }
    return self;
}

- (void)setupLoginCommand{

    @weakify(self);
    // 初始commadn
    self.loginCommand = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
       // 网络信号  --- 成功 -- 失败 -- 状态
        NSLog(@"input === %@",input);
        @strongify(self);
        return [self.loginM loginRequest:self.account pwd:self.password];
    }];
    
    // 成功
    [[self.loginCommand.executionSignals switchToLatest] subscribeNext:^(id  _Nullable x) {
        NSLog(@"switchToLatest == %@",x);
        @strongify(self);
        self.islogining = NO;
        User *user = x[@"info"];
        [self.statusSubject sendNext:[NSString stringWithFormat:@"登录成功-->%@",user.name]];
    }];
    // 失败
    [self.loginCommand.errors subscribeNext:^(NSError * _Nullable x) {
        NSLog(@"errors == %@",x);
        @strongify(self);
        self.islogining = NO;
        [self.statusSubject sendNext:@"登录失败"];

    }];
    // 状态 一般是0-1-0(未执行-开始执行-结束) 所以跳过第一个信号
//    [[self.loginCommand.executing skip:1] subscribeNext:^(NSNumber * _Nullable x) {
//        NSLog(@"executing == %@",x);
//        if ([x boolValue]) {
//            [self statusLableAnimation];
//        }
//    }];
    //第二种方式 直接忽略0
    [[self.loginCommand.executing ignore:@(0)] subscribeNext:^(NSNumber * _Nullable x) {
        @strongify(self);
        if ([x boolValue]) {
            [self statusLableAnimation];
        }
    }];
}
- (void)statusLableAnimation{
    self.islogining = YES;
    [self.statusSubject sendNext:@"正在登录"];
    
}

四、LoginM -- 提供数据

  • LoginM.h
#import <Foundation/Foundation.h>
#import <ReactiveObjC.h>
@interface User : NSObject
@property (nonatomic,copy) NSString *account;
@property (nonatomic,copy) NSString *name;
@end

@interface LoginM : NSObject
- (RACSignal *)loginRequest:(NSString *)account pwd:(NSString *)pwd;
@end
  • LoginM.m
#import "LoginM.h"
@implementation User
@end

@implementation LoginM
- (RACSignal *)loginRequest:(NSString *)account pwd:(NSString *)pwd{
    
    return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        // 抽取 -- 网络
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
            if ([account isEqualToString:@"123"] && [pwd isEqualToString:@"123"]) {
                User *user = [User new];
                user.account = account;
                user.name = @"小明";
                [subscriber sendNext:@{@"info":user}]; // 序列化 --- [model class] -- @[model,model]
                [subscriber sendCompleted];
            }else{
                NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:100868 userInfo:@{@"LGError":@"fail"}];
                [subscriber sendError:error];
            }
        });
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"请求网络信号销毁了");
        }];
    }];
}
@end

五、总结

相关文章

  • IOS RAC实践

    前言 RAC使用-->IOS RAC使用 -- ReactiveObjC 本文使用RAC+MVVM来模拟用户登录 ...

  • (一)、iOS RAC - RACSignal

    (一)、iOS RAC - RACSignal (二)、iOS RAC - RACDisposable(三...

  • 2019-12-10

    iOS开发之RAC(一)初级篇 一、RAC是什么? 1、RAC全称:ReactiveCocoa, Github 一...

  • 【other】Rac EventBus RxJava

    聊一聊 Rac Rac 是什么 Rac 全称 Reactivecocoa,是一个应用于iOS和OS X开发的框架,...

  • iOS 基于MVVM + RAC + ViewModel-Bas

    iOS 基于MVVM + RAC + ViewModel-Based Navigation的微信开发 iOS 基于...

  • iOS 基于MVVM + RAC + ViewModel-Bas

    iOS 基于MVVM + RAC + ViewModel-Based Navigation的微信开发(二) iOS...

  • iOS MVVM + RAC

    iOS MVVM + RAC https://www.jianshu.com/p/119559ac0961 IOS...

  • RAC

    IOS响应式编程框架ReactiveCocoa(RAC)使用示例 感觉RAC响应起来太乱,不太实用,但是平时自己的...

  • RAC开篇编程思想:Masory中的链式编程思想

    RAC是github开源的iOS和OS开发的框架,全称ReactiveCocoa。RAC主要应用函数响应式编程思想...

  • RAC基础

    最近接触学习到了RAC(ReactiveCocoa),RAC是函数式+响应式编程结合 我们在iOS开发中,页面之间...

网友评论

      本文标题:IOS RAC实践

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