RAC

信号

创建一个信号,每次订阅它可以执行它的block,并且在订阅的block中拿到它的sendxxx.

  • 用于经常执行一个事件。 例如:计数器
  • 将逻辑代码封装在信号中,在订阅block中触发信号事件并做收尾代码。
  • 当创建信号中的block中的subscriber(订阅者)执行到sendCompeleted或者sendError则销毁订阅(该订阅block不会再因为subscribe的sendNext触发)
  • 信号对象每次调用subscribeNext时会执行创建信号时subscriber所发送的所有sendNext直到遇到sendCompeleted或者sendError结束订阅触发disposableBlock

示例:

__block int i = 0;
RACSingal *singal = [RACSingal createSingal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {
    //doSomthing...
    [subscriber sendNext:@(++i)];
    [subscriber sendCompeleted];
    [subscriber sendError:$error];
    retrun [RACDisposable disposableWithBlock:^{
        //doSomthing...
    }];
}];
[signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%li",[x integerValue]); // 1;
    }];
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%li",[x integerValue]); // 2;
    }];
    [signal subscribeCompleted:^{
        NSLog(@"completed");       // completed;
    }];
    [signal subscribeError:^(NSError * _Nullable error) {
        NSLog(@"%@",error);    //$error
    }];
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"%li",[x integerValue]); //5;
    }];

所有类总结

  • 主要就是用信号来触发事件 RACSingnal是基类
  • RACSubject 是先订阅后发送信号 后执行所有订阅的block
  • RACReplaySubject 是先发送信号 后每订阅一次则触发所有信号执行订阅block
  • RACCommand UI控件会有一个rac_commend类别属性 传入一个RACCommand即可监听控件事件
  • RAC($target,$prop)=xxxSingnal 可以给某个类的某个属性绑定一个信号.当信号sendNext:xxx(发送信号)时该属性会随之更改。

例:

//当文本框修改时会触发信号subscribe的sendNext:输入的内心,此时就能被obj的prop订阅的block接收到 并进行修改prop的值
RAC(obj,prop) = textField.rac_textSignal;
    //用定时器修改UILabel
    _subject = [RACSubject subject];
    RAC(label,text) = _subject;
    __block int i = 0;
    @weakify(self)
    [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        @strongify(self)
        if (++i>20) {
            [timer invalidate];
        }
        [self.subject sendNext:[NSString stringWithFormat:@"%i",i]];
        
    }];

UITextField有一个rac_textSignal属性可以监听它触发事件,
UIButton拿到事件信号[[UIButton buttonWithType:UIButtonTypeRoundedRect] rac_signalForControlEvents:UIControlEvents]


*RACCommand

  • 该类是信号的封装
  • 创建时调用一个带有传入参数返回信号的block

//    创建指令
    RACCommand *commend = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id _Nullable x) {
        return [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {
            YPLog(@"%@",x);
            [subscriber sendNext:@"next"];
            return nil;
        }];
    }];
//    执行指令获取信号 并订阅
    [[commend execute:@"execute"] subscribeNext:^(id  _Nullable x) {
        YPLog(@"%@",x);
    } ];
//    指令只能执行一次 重复执行无效
    [commend execute:@"execute2"];
    

*Filter(过滤信号值) Map(转换信号值) doNext(预处理)

  • filter [$racSingal filter:^BOOL(id _Nullable x){}]filter返回一个BOOL值,用filter过滤信号发出的(sendNext)值,当满足filter方法时才会执行后面订阅的block.
  • map [$racSingal filter:^id(id _Nullable x){}]map返回一个新的对象,将之前接收到的值进行处理返回一个新的值.然后执行后面订阅的block
  • doNext doNext可以像subscribeNext一样获取到sendNext值但是它会返回信号给后面的订阅方法。

实例:

_subject = [RACSubject subject];
//    用filter map进行转换信号传递的值
//    每次filter map返回的都是一个新的信号
    RACSignal *signal = [[_subject filter:^BOOL(id  _Nullable value) {
        return [value integerValue] >5;
    }] map:^id _Nullable(id  _Nullable value) {
        return [NSString stringWithFormat:@"第%li个",[value integerValue]];
    }];
    
    RAC(label,text) = signal;
    __block int i = 0;
    @weakify(self)
    [NSTimer scheduledTimerWithTimeInterval:1 repeats:YES block:^(NSTimer * _Nonnull timer) {
        @strongify(self)
        i++;
        if (i>20) {
            [timer invalidate];
        }
        [self.subject sendNext:[NSString stringWithFormat:@"%i",i]];
        
    }];
    
    

*flattenMap then 返回一个新的信号

  • 给信号调用flattenMap从block中返回一个新的信号来替换原来的信号。
  • then和flattenMap的作用一样 不过then需要等待上一个信号执行了sendCompelete才会返回一个新的信号给下一个,一些UI控件是不会执行sendCompelete的.
  • 因为subscribe一旦执行sendComplete就会销毁当前订阅,UI控件则不发送sendCompelete,让该信号的订阅block可以一直触发

  • UI控件的信号使用flattenMap来替换信号
  • 异步操作(网络请求等)使用then来替换信号

注意:

  • 和上面的map区别 map只是对信号发送的值进行转换 flattenMap是替换该信号
  • 订阅信号的error时 如果信号某个阶段执行sendError则直接进入error的block

*CombineLatest聚合

  • combineLatest 聚合函数可以使多个不同的信号合并成一个新的信号,当所有信号的subscribe都发送出sendNext的时候就会调用合并信号后订阅的block
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {
        [subscriber sendNext:@"hello"];
        return nil;
    }];
    RACSubject *subject = [RACSubject subject];
    RACSignal *combineSignal = [RACSignal combineLatest:@[signal,subject] reduce:^id _Nullable(NSString*str1,NSString*str2){
        YPLog(@"%@, %@",str1,str2);
        return [str1 stringByAppendingString:str2];
    }];
    [combineSignal subscribeNext:^(id  _Nullable x) {
        YPLog(@"%@",x);
    }];
    //当该信号触发才会触发合并的信号
    [subject sendNext:@"vijay"];
  • 注意:一个信号添加了监听后除非手动调用信号的dispose(清空信号的监听),则监听会一直保留在信号上,重复监听则会重复叠加 千万不要重复叠加监听
  • 可以同时监听sendNext sendError sendCompelete subscribeNext:^(id _Nullable x)nextBlock error:^(NSError * _Nullable error)errorBlockcompleted:^(void)completedBlock:

登录示例:

- (void)loginServiceWith:(NSString*)username :(NSString*)password compelete:(void(^)(BOOL result))callback{
    callback(username.length&&password.length);
}

- (RACSignal*)loginSignal{
    @weakify(self)
    return [RACSignal createSignal:^RACDisposable * _Nullable(id  _Nonnull subscriber) {
        @strongify(self)
        [self loginServiceWith:self.userNameField.text :self.passWordField.text compelete:^(BOOL result) {
            [subscriber sendNext:@(result)];
            [subscriber sendCompleted];
        }];
        
        return nil;
    }];
    
}




- (void)viewDidLoad {
    [super viewDidLoad];
    [self createUI];
    
    [[[[self.loginBtn rac_signalForControlEvents:UIControlEventTouchUpInside] doNext:^(__kindof UIControl * _Nullable x) {
        self.loginBtn.enabled = NO;
        self.failText.hidden = YES;
    }] flattenMap:^__kindof RACSignal * _Nullable(__kindof UIControl * _Nullable value) {
        return [self loginSignal];
     }] subscribeNext: ^(id  _Nullable x) {
        self.loginBtn.enabled = YES;
        BOOL success = [x boolValue];
        self.failText.hidden = success;
        if (success) {
            [SVProgressHUD showSuccessWithStatus:@"登录成功"];
        }
    }completed:^{
        YPLog(@"compelete");
    }];

    
}

替代代理

//给当前控制器对象的代理方法转换成信号并监听
 [[self rac_signalForSelector:@selector(tableView:didSelectRowAtIndexPath:) fromProtocol:@protocol(UITableViewDelegate) ] subscribeNext:^(RACTuple * x) {
//  RACTuple是一个类数组(元组)里面保存了代理方法的所有参数
    }];
//当tableview触发代理方法时就会激活该信号 并且执行订阅的block    
table.delegate = self;

你可能感兴趣的:(RAC)