美文网首页
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实践

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