ReactiveCocoa信号高阶操作

来源:互联网 发布:淘宝虾米vip怎么领取 编辑:程序博客网 时间:2024/05/21 10:52
一 升阶和降阶

二 
1.创造高阶信号
(1)RACSignal*signal = [RACSignalreturn:@1];
RACSignal*signalHighOrder = [RACSignalreturn:signal];

(2)RACSignal *anotherSignal = [signalmap:^id(idvalue) {
       return [RACSignalreturn:value];
}];

2.订阅高阶信号
RACSignal*signal =@[@1,@2,@3].rac_sequence.signal;
RACSignal*highOrderSignal = [signalmap:^id(idvalue) {
       return [RACSignalreturn:value];
  }];
[highOrderSignalsubscribeNext:^(RACSignal*aSignal) {
        [aSignalsubscribeNext:^(idx) {
           // get real value here.
}]; }];

三 降阶操作
1.SwitchToLatests
信号1 信号2(将信号1关闭) 信号4 信号5与高阶信号 信号6 信号7 判断信号是否结束



示例一
RACSignal*autoRunButtonClickSignal = [self.autoRunBtn rac_signalForControlEvents:UIControlEventTouchUpInside];

RACSignal*oneStepButtonClickSignal = [self.oneStepBtn
rac_signalForControlEvents:UIControlEventTouchUpInside];

RACSignal*idSignal = [RACSignalreturn:nil];
RACSignal*timerSignal = [RACSignalinterval:1 onScheduler:[RACScheduler mainThreadScheduler]];
autoRunButtonClickSignal = [autoRunButtonClickSignalmapReplace:idSignal];
oneStepButtonClickSignal = [oneStepButtonClickSignalmapReplace:timerSignal];
RACSignal*controlSignal = [autoRunButtonClickSignalmergeoneStepButtonClickSignal];
controlSignal = [controlSignal switchToLatest];

示例二 搜索请求
网络差 连续发送不同的请求 有时后搜索的会先返回 造成搜索不准
RACSignal*searchTextSignal = [self.searchTextField rac_textSignal];
RACSignal*requestSignals = [searchTextSignalmap:^id(NSString*searchText) {
       NSString *urlString = [NSStringstringWithFormat:
                              @"http://xxxx.xxx.xxx/?q=%@", searchText];
       NSURL *url = [NSURLURLWithString:urlString];
       NSURLRequest *request = [NSURLRequestrequestWithURL:url];
        return [NSURLConnectionrac_sendAsynchronousRequest:request];
    }];  
//第二个信号去请求时会把第一个信号关掉
    requestSignals = [requestSignals switchToLatest];

2.If/then/else

If/then/else本质&类似操作

+ (RACSignal*)if:(RACSignal*)boolSignal
then:(RACSignal*)trueSignal
else:(RACSignal*)falseSignal {
   return [[boolSignal
            map:^(NSNumber*value) {
                return (value.boolValue? trueSignal : falseSignal);
             }]
           switchToLatest];
}

+ (RACSignal*)switch:(RACSignal*)signal
cases:(NSDictionary*)cases
default:(RACSignal*)defaultSignal;

3.Flatten  不会丢数据 扁平

异步 并发 同时允许2段并发(此时已经满了,黄色和绿色信号)   绿色信号或黄色信号结束了橙色信号才会开始



Flatten:1的思考
-返回 a 信号,b 信号的高阶信号 flatten:1 相当于 a信号concat:b信号
- (RACSignal *)concat;
concat 与1秒延迟信号

RACSignal *signal = @[@1, @3, @7,@9, @8].rac_sequence.signal;
RACSignal *timerSignal = [[signal map:^id(id value) {
return [[RACSignal return:value] delay:1];
}] concat];

降阶操作总结
SwitchToLatests (将上一个信号抛弃)
Flatten (Merge)
Concat (Flatten:1)

四 思考

1.改变某个值的个数 
返回的是1,2,2,3,3,3
RACSignal *signal = @[@1, @2, @3].rac_sequence.signal;
RACSignal *mappedSignal = [[signal map:^id(NSNumber *value) {
return [[[RACSignal return:value] repeat]             take:value.integerValue]; 
}] flatten];

2.将一个值改为一个错误
 RACSignal *signal = @[@1,@2,@3,@0].rac_sequence.signal;
   RACSignal *mappedSignal = [[signal map:^id(NSNumber *value) {  if(value.integerValue ==0) {
            return [RACSignal error:[NSError errorWithDomain:@"0"code:0 }else {
return[RACSignalreturn:value];
}
}] flatten];

3.改变值的时间间隔
RACSignal *signal = @[@"♪5",@"♬1",@"♬2",@"♬3",@"♩4"]
    .rac_sequence
    .signal;
NSDictionary*toneLengthMap =@{@"♩":@0.5,
                                   @"♪":@0.25,
                                    @"♬":@0.125};

RACSignal*mappedSignal = [[signalmap:^id(NSString*value) {
       NSString *tone = [value substringFromIndex:1];
       NSString *length = [value substringToIndex:1];
       NSNumber *toneValue = @(tone.integerValue);
       NSNumber *toneLength = toneLengthMap[length];
       return [[RACSignalreturn:toneValue]
               concat:[[RACSignalempty]
                       delay: toneLength.doubleValue]];
        }] concat];
delay 是不靠谱的(concat一个 empty 信号,delay 延长)

4.Map————>Flatten  FlattenMap 高阶>降阶

五  FlattenMap
1.重要性
可以用 FlattenMap 实现很多的信号转换
支持串行异步操作(类似 Promise)
满足 Monad 部分定义 (bind 和 return 才完全满足)

FlattenMap要求传入信号,然后返回扁平化后的 value
RACSignal*flatten = [signal flattenMap:^RACStream *(RACSignal *value) {
       return value;
    }];
RACSignal*map = [signal flattenMap:^RACStream *(idvalue) {
       id anotherValue = value;// map here!
       return [RACSignal return: anotherValue];
    }];
过滤掉空的值
RACSignal*filter = [signal flattenMap:^RACStream *(idvalue) {
       BOOL filter = (value ==nil);// filter here!
       return filter ? [RACSignal empty] : [RACSignal return:value];
    }];


在实际使用时的重要场景
RACSignal*signal = [RACSignalreturn:@"http://xx.com/a"];
RACSignal*getSignal = [signalflattenMap: ^RACStream*(NSString*url) {
       NSURLRequest *request = [NSURLRequestrequestWithURL:[NSURLURLWithString:url]];
       return [NSURLConnectionrac_sendAsynchronousRequest:request];
    }];
RACSignal*jsonSignal = [getSignalflattenMap: ^RACStream*(NSData*data) {
       NSError *error = nil;
       id result = [NSJSONSerializationJSONObjectWithData:dataoptions:0error:&error];
        return error ==  nil ? [RACSignalreturn:result]: [RACSignalerror: error];
    }];
RACSignal*getItemSignal = [jsonSignalflattenMap: ^RACStream*(NSDictionary*value) {
       if (![valueisKindOfClass:[NSDictionaryclass]] || value[@"data.url"] == nil) {
           return [RACSignal error:someError];
        }
        NSURLRequest *anotherRequest = [NSURLRequestrequestWithURL:[NSURLURLWithString:value[@"data.url"]]];
       return [NSURLConnectionrac_sendAsynchronousRequest:anotherRequest];
    }];


2.FlattenMap 与 monad,bind
  • Functor,Applicative,Monad 概念
  • FlattenMap 符合 Monad 的 bind 定义,但是无法实现 takeUntil:操作,无法做副作用操作例如 take:的计数
   
 - (instancetype)flattenMap:(RACStream * (^)(idvalue))block;
 - (instancetype)bind:(RACStreamBindBlock (^)(void))block;
    typedef RACStream * (^RACStreamBindBlock)(idvalue,BOOL *stop);

3.bind妙用
- (RACSignal*)take:(NSUInteger)count {
   if (count ==0)return [RACSignalempty];
   return [selfbind:^{
       __block NSUInteger taken = 0;
       return ^ id (idvalue,BOOL *stop) {
           if (taken < count) {
                ++taken;
               if (taken == count) *stop =YES;
               return [class return:value];
            }else {
               return nil; }
        }; }];
}

4.bind简单实现和问题
- (RACSignal*)bind:(RACStreamBindBlock(^)(void))block;
{
   return [RACSignalcreateSignal:^RACDisposable*(id<RACSubscriber> subscriber) {
       RACStreamBindBlock bindBlock = block();
        [selfsubscribeNext:^(idx) {
           BOOL stop =NO;
            RACSignal *signal = (RACSignal *)bindBlock(x, &stop);
           if (signal ==nil || stop) { [subscriber sendCompleted];
            }else {
                [signal subscribeNext:^(idx) { [subscriber sendNext:x];
                } error:^(NSError *error) { [subscriber sendError:error];
                } completed:^{ }];
            }
        } error:^(NSError *error) { [subscriber sendError:error];
        } completed:^{ [subscriber sendCompleted]; }];
       return nil;
    }]; }


六 有用的高阶操作
- (RACSignal *)try:(BOOL(^)(idvalue, NSError **errorPtr))tryBlock;  对每个值进行分析,用来简化 flattenMap 等操作
- (RACSignal*)tryMap:(id(^)(idvalue, NSError **errorPtr))mapBlock;
- (RACSignal *)catch:(RACSignal * (^)(NSError *error))catchBlock;
- (RACSignal*)catchTo:(RACSignal*)signal;
- (RACSignal *)timeout:(NSTimeInterval)interval
           onScheduler:(RACScheduler *)scheduler;


七 扩展问题
不能 信号是 pushDriver 只能被动接收 浓缩信号变短(冷热信号操作)