RAC响应式编程---iOS笔记摘录

目录

前言

RAC(ReactiveCocoa) 
    函数式编程、响应式编程    
    Github上的开源框架

响应式编程,是一种通用的编程范式,提高了开发效率。
我的理解就是:监听事件,然后在事件发生后做相应回调处理。
/**
delegate、通知、block
KVO
*/
在命令式编程环境中,a=b+c表示将表达式的结果赋给a,而之后改变b或c的值不会影响a。
但在响应式编程中,可以做到a的值随b或c的更新而更新。
RAC框架图

1. 使用

引入(集成ReactiveCocoa框架)
    pod 'ReactiveObjC'
    #import <ReactiveObjC/ReactiveObjC.h>
  1. 常用
添加监听事件
    // 给UITextFiled添加值改变事件
    [[[UITextField new]rac_signalForControlEvents:UIControlEventEditingChanged]subscribeNext:^(id x) {
        //
    }];
    等同于(简化版)
    [[[UITextField new]rac_textSignal]subscribeNext:^(NSString * _Nullable x) {
        // UIControlEventEditingChanged
    }];

    // 给按钮添加点击事件
    [[self.button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
添加手势
    [[UIButton new]addGestureRecognizer:({
        UITapGestureRecognizer *tapG=[UITapGestureRecognizer new];
        [[tapG rac_gestureSignal]subscribeNext:^(__kindof UIGestureRecognizer * _Nullable x) {
        }];
        tapG;
    })];
调用方法
    @weakify(self)
    [[self rac_signalForSelector:@selector(viewDidLoad)]subscribeNext:^(id x) {
        @strongify(self)
        //
    } error:^(NSError * _Nullable error) {
    } completed:^{
    }];
dele代理
    UIAlertView *alertV=[[UIAlertView alloc]initWithTitle:@"alert" message:@"content" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles:@"sure", nil];
    // 实现代理方法clickedButtonAtIndex 来自协议UIAlertViewDelegate
    [[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)]subscribeNext:^(id  _Nullable x) {
    }];
    // 等同于(简化版)
    [[alertV rac_buttonClickedSignal]subscribeNext:^(NSNumber * _Nullable x) {
    }];
    [alertV show];
NSNotificationCenter通知
    添加观察者
    [[[NSNotificationCenter defaultCenter]rac_addObserverForName:@"notiName" object:nil]subscribeNext:^(NSNotification * _Nullable noti) {
        // noti.name noti.object noti.object
    }];
    发送通知
    [[NSNotificationCenter defaultCenter]postNotificationName:@"notiName" object:@[@"1",@"2"]];
KVO键值观察
    // 方式一
    [RACObserve([UIScrollView new], contentOffset) subscribeNext:^(id  _Nullable x) {
    }];
    // 方式二
    [[self rac_valueForKeyPath:@"age" observer:nil] subscribeNext:^(id x ){
        NSLog(@"%@",x);
    }];
RACSubject
    // 用于view中不同button的点击事件
    RACSubject *subj=[RACSubject subject];
    [subj sendNext:@(100)];
    // 外部调用
    [subj subscribeNext:^(NSNumber *tag) {
    }];
    
cell.clickSubject 
    @weakify(self);
    [[cell.clickSubject takeUntil:cell.rac_prepareForReuseSignal] subscribeNext:^(NSNumber *x) {
        @strongify(self);
        [self clickCellBtn:[x intValue] atIndex:indexPath];
    }];
值绑定

RAC(self.label.text) = _textField.rac_textSignal;
RAC(_personVM,mobile)=_phoneTF.rac_textSignal;
  1. 接口命令(用于MVVM)
+(RACSignal *)PostWithURL:(NSString *)urlStr parameters:(NSDictionary *)paramDic animated:(BOOL)animated{
    return [[RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        
            [YTNetworkTool POST:urlStr parameters:paramDic SuccessBlock:^(BOOL isOK, NSDictionary *dic) {
                // 回调
                [subscriber sendNext:dic];
                [subscriber sendCompleted];
            } failBlock:^(NSError *error) {
                [subscriber sendError:error];
            } animated:animated];
    
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"信号发送完成或发送错误后调用,会自动执行这个block,并取消订阅信号");
        }];
    }]replayLazily];
}
    _addRouteCommand=[[RACCommand alloc]initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
        //
        NSDictionary *paramDic=@{@"isOpen":self.isOpen};
        return [YTServiceObject PostWithURL:API_AddRouteT parameters:paramDic animated:true];
    }];
    执行命令(调用接口)
    vm.isOpen=@(true);
    [[vm.addRouteCommand execute:nil] subscribeNext:^(NSDictionary *dic) { 
      // dic
    }];
    [[[vm.addRouteCommand execute:nil]deliverOnMainThread] subscribeNext:^(NSDictionary *dic) { 
      // dic
    }];

    // 命令在执行中(用于加载 加载中...)
    [[vm.addRouteCommand executing]subscribeNext:^(NSNumber * _Nullable x) {
        if(x.boolValue){
            // 加载 加载中...
        }else{
            // 隐藏 加载中...
        }
    }];

两个信号都收到时回调

RACSignal*signalA = [RACSignal createSignal:^RACDisposable *(id <RACSubscribe>subscriber){
  NSLog(@"数据请求1");
[subscriber sendNext:@"数据请求1请求下来的数据"];
return nil;
}];
RACSignal*signalB = [RACSignal createSignal:^RACDisposable *(id <RACSubscribe>subscriber){
  NSLog(@"数据请求2");
[subscriber sendNext:@"数据请求2请求下来的数据"];
return nil;
}];
[self rac_liftSelector:@Selector(updateUI) withSignalFromArray:@[signalA,signalB]];
 //将 textfield 输入信号的 返回值进行修改  得到新的信号!
    RACSignal *firstSignal = [self.firstTextfield.rac_textSignal map:^id(NSString *firstString) {
        if (firstString.length >= 5 && firstString.length <= 10) {
            return @(YES);
        }
        return @(NO);
    }];
     RACSignal *secondSignal = [self.secondTextfield.rac_textSignal map:^id(NSString *secondString) {
         if (secondString.length >5 && secondString.length < 10) {
             return @(YES);
         }
         return @(NO);
     }];
    // 绑定用户名、密码判断结果的2个信号量,如果都为真,则按钮可用
    RAC(self.loginButton,enabled) = [RACSignal combineLatest:@[firstSignal,secondSignal] reduce:^(NSNumber *firstRes,NSNumber *secondRes){
        return @(firstRes.boolValue && secondRes.boolValue);
    }];
  1. 信号加条件
map 映射(拦截做额外处理)

    [[[self.button rac_signalForControlEvents:UIControlEventTouchUpInside]map:^id(id value) {
        NSLog(@"value: %@",value);
        return @"hello";
    }]subscribeNext:^(id x) {
        NSLog(@"%@",x);
    }];
filter 过滤(拦截不符合情况)

    // 监听文本框的输入,而且只有大于3个长度的时候才会打印
    [[self.textField.rac_textSignal filter:^BOOL(id value) {
        return [value length] > 3;
    }]subscribeNext:^(id x) {
        NSLog(@"x:%@",x);
    }];
延时

[[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
}];

[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * date) {
}];

take:2   选取前两个信号
skip:2   跳过前两个信号
repeat   无限重复执行
delay:3  延迟3s发送信号
throttle:0.5           0.5s内信号不发生变化则触发
distinctUntilChanged   不会连续发送两次相同的信号
timeout:2       超时2s后触发error
ignore:@"1"     忽略信号1


[[self.button rac_signalForControlEvents:UIControlEventTouchUpInside] subscribeNext:^(id x) {
        [self.textField endEditing:YES];
        //        [alertView show];
      
        // 创建信号
        RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
            [subscriber sendNext:@"1"];
            [subscriber sendNext:@"2"];
            [subscriber sendNext:@"3"];
            [subscriber sendNext:@"4"];
            [subscriber sendCompleted];
            return nil;
        }] take:2];  // skip:2、repeat
        
        // 发送信号
        [signal subscribeNext:^(id x) {
            NSLog(@"x : %@",x);
        } completed:^{
            NSLog(@"completed");
        }];
    }];
将多个不同类型的数据组合成一个元组
    // 把参数中的数据包装成元组
    RACTuple *tuple = RACTuplePack(@"xmg",@20,@"m",@(999),@[@"a"],@{@"key":@"value"});
    
    RACTupleUnpack(NSString *name,NSNumber *age,NSString *sex,NSNumber *price,NSArray *arr,NSDictionary *dic) = tuple;
    NSLog(@"name:%@  age:%@  sex:%@  price:%@ arr:%@  dic:%@",name,age,sex,price,arr,dic);

遍历数组、字典

    NSArray *contentArr=@[@"hello",@"world",@"!"];
    [contentArr.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
    }];

    NSDictionary *paramDic=@{@"hello":@"world"};
    [paramDic.rac_sequence.signal subscribeNext:^(id  _Nullable x) {
        RACTwoTuple *tuple=(RACTwoTuple *)x;
        // key: tuple[0]
        // value: tuple[1]
    }];
  1. 基础
信号RACSignal
    // 1. 创建信号
    RACSignal *signalA = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 3. 发送信号
        [subscriber sendNext:@"唱歌"];
        // 调用该方法销毁信号,否则该信号一直占用着内存
        [subscriber sendCompleted];
        // 3.1 发送error信号
        [subscriber sendError:[NSError errorWithDomain:NSURLErrorDomain code:1001 userInfo:@{@"error":@"error message"}]];
        // 4. 销毁信号完毕后回调
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"singal已销毁");
        }];
    }];
    // 2. 订阅信号
    RACDisposable *disposable = [signalA subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];
    // 取消订阅
    // [disposable dispose];
    // 2.1 订阅error信号
    [signalA subscribeError:^(NSError * _Nullable error) {
        NSLog(@"%@",error);
    }];


信号动作:
  信号映射:map、flattenMap
  信号过滤:filter、ignore、distinctUntilChanged
  信号合并:combineLatest、reduce、merge、zipWith
  信号连接:concat、then
  信号操作时间:timeout、interval、dely
  信号跳过:skip
  信号取值:take、takeLast、takeUntil
  信号发送顺序:donext、cocompleted
  获取信号中的信号:switchToLatest
  信号错误重试:retry
避免循环引用
  @weakify(self)
  @strongify(self)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容