RAC笔记

//signal1,signal2有任何一个被订阅,即x等于一个RACTuple
RACSignal *signal1 = [ RACSignal defer :^ RACSignal *{
        NSLog ( @"aaaa" );
       
return [ RACSignal return : @"hello111" ];
    }];
   
   
RACSignal *signal2 = [ RACSignal defer :^ RACSignal *{
       
NSLog ( @"bbbb" );
       
return [ RACSignal return : @"hello222" ];
    }];
RACSignal *signal3 =[ RACSignal combineLatest : @[ signal1,signal2 ] ];
    [signal3 subscribeNext :^( id x) {
       
NSLog ( @"x = %@" ,x);
    }];

//先处理signal2 再处理signal1 ,当两个信号都sendNext后,signal3才会触发
- ( RACSignal *)zipWith:( RACSignal *)signal
    RACSignal *signal1 = [ RACSignal defer :^ RACSignal *{
       
NSLog ( @"aaaa" );
       
return [ RACSignal return : @"hello111" ];
    }];
   
   
RACSignal *signal2 = [ RACSignal createSignal :^ RACDisposable *( id < RACSubscriber > subscriber) {
       
NSLog ( @"bbbbb" );
        [subscriber
sendNext : @"asdfasdf" ];
        [subscriber
sendCompleted ];
       
return nil ;
    }];
   
   
RACSignal *signal3 = [signal2 zipWith :[signal1 logAll ]];
   
    [signal3
subscribeNext :^( id x) {
       
NSLog ( @"asdfasdf" );
    }
completed :^{
       
NSLog ( @"asdfasdfsdf" );
    }];
// RACSignal combineLatest :与 zipWith :实际上结果是一样的.都是等到所有的signal被sendNext后,才会触发


//concat
RACSignal *signal3 = [signal2 concat :[signal1 logAll ]];
/// Subscribes to `signal` when the source signal completes.
- (RACSignal *)concat:(RACSignal *)signal;
当signal2 被sendCompleted后,就去订阅signal1

    RACSignal *signal1 = [ RACSignal defer :^ RACSignal *{
       
NSLog ( @"print signal1" );
       
return [ RACSignal return : @"signal1" ];
    }];
   
   
RACSignal *signal2 = [ RACSignal defer :^ RACSignal *{
       
NSLog ( @"print signal2" );
       
return [ RACSignal return : @"signal2" ];
    }];
   
   
RACSignal *signal3 = [signal1 concat :signal2];
    [signal3
subscribeNext :^( id x) {
       
NSLog ( @"%@" ,x);
    }];

2015-06-03 13:23:00.381 DemoCategorizer[21572:2556481] print signal1
2015-06-03 13:23:07.385 DemoCategorizer[21572:2556481] signal1
2015-06-03 13:23:07.385 DemoCategorizer[21572:2556481] print signal2
2015-06-03 13:23:16.748 DemoCategorizer[21572:2556481] signal2

//skip
skip:( NSUInteger )skipCount
//跳过第 skipCount 个sendNext,从后面取
RAC ( self .secCodeImageView,image) = [[ RACObserve ( self .viewModel,secCodeimageFile) skip : 1 ] map :^ id ( id value) {
       
NSLog ( @"secCodeimageFile == %@" ,value);
       
return [[ UIImage alloc ] initWithContentsOfFile :value];
    }];
// secCodeimageFile第一次为nil,可以通过skip跳过



//catch
/// Subscribes to the returned signal when an error occurs.
- (RACSignal *)catch:(RACSignal * (^)(NSError *error))catchBlock;

    RACSignal *signal1 = [ RACSignal createSignal :^ RACDisposable *( id < RACSubscriber > subscriber) {
        [subscriber
sendError :[ NSError errorWithDomain : @"my fault" code : 100 userInfo : nil ]];
       
return [ RACDisposable disposableWithBlock :^{
           
NSLog ( @"done" );
        }];
    }];
   
   
RACSignal *signal2 = [signal1 catch :^ RACSignal *( NSError *error) {
       
NSLog ( @"catch error" );
       
return [ RACSignal return : @"idiot" ];
    }];
   
    [signal2
subscribeNext :^( id x) {
       
NSLog ( @"x = %@" ,x);
    }];
//catch用于,封装一个错误处理机制的signal,也就是当signal1出现了错误,将创建一个新的错误处理signal2,完成后并处理订阅者的流程
打个比方,如果要为服务器上某个商品点赞+1,但是出现了网络不同,此时,就要把UserDefault里的值减1.

/// Subscribes to the given signal when an error occurs.
- (RACSignal *)catchTo:(RACSignal *)signal;

    RACSignal *signal1 = [ RACSignal createSignal :^ RACDisposable *( id < RACSubscriber > subscriber) {
        [subscriber
sendError :[ NSError errorWithDomain : @"my fault" code : 100 userInfo : nil ]];
       
return [ RACDisposable disposableWithBlock :^{
           
NSLog ( @"done" );
        }];
    }];
   
   
RACSignal *signal2 = [signal1 catchTo :[ RACSignal return : @"my falut" ]];
    [signal2
subscribeNext :^( id x) {
       
NSLog ( @"x = %@" ,x);
    }];

catch与 catchTo的目标是相同的,区别在于catch提供了一个处理error的机会,而catchTo直接无视error


//try
- ( RACSignal *) try :( BOOL (^)( id value, NSError **errorPtr))tryBlock;
    RACSignal *signal1 = [[ RACSignal createSignal :^ RACDisposable *( id < RACSubscriber > subscriber) {
       
// 处理一个网络请求 , 当成功后把结果 okok 发送出去
        [subscriber
sendNext : @"okok" ];
        [subscriber
sendCompleted ];
       
return [ RACDisposable disposableWithBlock :^{
           
NSLog ( @"done" );
        }];
    }]
try :^ BOOL ( NSString *s, NSError * __autoreleasing *errorPtr) {
       
// 在这里尝试判断 signal 的结果 , 当收到了 Next , 判断其值 , 如果结果与预期一样就 , 告诉订阅者
       
// 比如网络请求的结果是对的
       
if ([s hasPrefix : @"ok" ]) {
           
return YES ;
        }
else {
           
return NO ;
        }
    }];
   
    [signal1
subscribeNext :^( id x) {
        NSLog(@“subscribed.%@“,x);
          //x == okok
    }];
- ( RACSignal *)tryMap:( id (^)( id value, NSError **errorPtr))mapBlock

try与tryMap都是为了判断一个signal是否sendNext,区别在于try可以根据结果来决定是否继续并且把kook发送给订阅方,而tryMap则会对值做一个转换再传给订阅方

//delay
- ( RACSignal *)delay:( NSTimeInterval )interval
//sendNext后,再触发subscriber

//deliverOn
- ( RACSignal *)deliverOn:( RACScheduler *)scheduler
deliverOn :[ RACScheduler scheduler ] //订阅者将在ReactiveCocoa创建的工作队列里收到sendNext
deliverOn :[ RACScheduler mainThreadScheduler ] //订阅者将在main thread创建的工作队列里收到sendNext

//if:then:else:
    RACSignal *signal1 = [ RACSignal createSignal :^ RACDisposable *( id < RACSubscriber > subscriber) {
        [subscriber
sendNext : @NO ];
        [subscriber
sendCompleted ];
       
return [ RACDisposable disposableWithBlock :^{
           
NSLog ( @"done" );
        }];
    }];
   
   
RACSignal *signal2 = [ RACSignal defer :^ RACSignal *{
       
NSLog ( @"bbbb" );
       
return [ RACSignal return : @"hello222" ];
    }];
   
   
RACSignal *signal3 = [ RACSignal defer :^ RACSignal *{
       
NSLog ( @"cccc" );
       
return [ RACSignal return : @"hello333" ];
    }];
   
   
    [[
RACSignal if :signal1 then :signal2 else :signal3] subscribeNext :^( id x) {
        NSLog(@"subscribed. %@",x);
//如果signal1 sendNext:@YES,就执行signal2的内容,否则就是signal3


startWith:
RAC ( self .intervalTextField,text) = [[[ RACSignal interval : 1 onScheduler :[ RACScheduler mainThreadScheduler ]] startWith : @"hello" ] map :^ id ( id value) {
       
return [ NSString stringWithFormat : @"text %d" ,count++];
    }];

第一次拿到的值为”hello,第二个才是text 0

RACAble/ RACAbleWithStart
反向绑定变量,当bindstring发生变化时,intervalTextField.text也会随着改变,但是反过来就不行
RAC ( self .intervalTextField,text) = RACAbleWithStart ( self .bindString);
RACAble 只是绑定, RACAbleWithStart是绑定后,立即对其赋值
    }];

merge/ combineLatest :
    RACSignal *combinding = [ RACSignal merge : @[self . textField1 . rac_textSignal , self . textField2 . rac_textSignal ] ];
   
    [combinding
subscribeNext :^( id x) {
       
NSLog ( @"%@" ,x);
    }
completed :^{
       
NSLog ( @"completed." );
    }];
共同点:当任何一个信号被触发,combinding都会被调起
不同点:merge时x只是被触发的textField内容,combineLatest会把两个textField的值用一个tuple来传入x


RACMulticastConnection public connect
当一个信号被订阅了几次,那么它将会执行几次,见下方代码:
    RACSignal *signal1 = [ RACSignal defer :^ RACSignal *{
       
NSLog ( @"print signal1" );
       
return [ RACSignal return : @"hello" ];
    }];
   
    [signal1
subscribeNext :^( id x) {
       
NSLog ( @"first %@" ,x);
    }];

    [signal1
subscribeNext :^( id x) {
       
NSLog ( @"second %@" ,x);
    }];
2015-06-05 14:35:38.149 DemoCategorizer[15252:2226982] print signal1
2015-06-05 14:35:38.149 DemoCategorizer[15252:2226982] first hello
2015-06-05 14:35:38.149 DemoCategorizer[15252:2226982] print signal1
2015-06-05 14:35:38.149 DemoCategorizer[15252:2226982] second hello
那么,我打算某个网络操作只做一次,然后多个订阅者都可以收到消息,怎么做?
    RACSignal *signal1 = [ RACSignal defer :^ RACSignal *{
       
NSLog ( @"print signal1" );
       
return [ RACSignal return : @"signal1" ];
    }];
   
   
RACMulticastConnection *connection = [signal1 publish ];
    [connection.
signal subscribeNext :^( id x) {
       
NSLog ( @"first next value = %@" ,x);
    }];
   
    [connection.
signal subscribeNext :^( id x) {
       
NSLog ( @"second next value = %@" ,x);
    }];
   
    [connection connect];
2015-06-05 14:38:48.528 DemoCategorizer[15848:2239991] print signal1
2015-06-05 14:38:48.528 DemoCategorizer[15848:2239991] first next value = signal1
2015-06-05 14:38:48.528 DemoCategorizer[15848:2239991] second next value = signal1
signal1只是被执行了一次,神奇不? 详见 http://www.jianshu.com/p/a0a821a2480f


+(RACSignal*)importPhotos{
    NSURLRequest *request = [self popularURLRequest];

    return [[[[[[NSURLConnection rac_sendAsynchronousRequest:request] 
                reduceEach:^id(NSURLResponse *response, NSData *data){
                            return data; 
                }]
                  deliverOn:[RACSchedulermainThreadScheduler]]
                map:^id(NSData*data){
                    id results = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
                    return [[[results[@"photos"] rac_sequence] 
                            map:^id(NSDictionary *photoDictionary){
                                    FRPPhotoModel *model = [FRPPhotoModel new];
                                    [self configurePhotoModel:model withDictionary:photoDictionary];
                                    [self downloadThumbnailForPhotoModel:model];
                                    return model; 
                            }] array];
                }] publish] autoconnect];
}
这里使用到了publish与 auto connect,我的理解是publish返回的是一个 RACMulticastConnection 
这是一个连接多个订阅者的handle
autoconnect的目的是返回一个RACSignal,它连接着多个订阅者,只要有一个订阅者订阅了该信号,那么该信号只会做一次,然后分发给多个订阅者结果.
希望自己将来能看懂.


RACReplaySubject
注意区分RACSubject和其子类RACReplaySubject的不同。RACReplaySubject只能被订阅一次,这避免了重复的重做。replay subject会存储返回的值,并把他们发送给新的订阅者-这正是我们需要的。
- ( RACReplaySubject *)importPhotos{
   
RACReplaySubject *subject = [[ RACReplaySubject alloc ] init ];
   
dispatch_after ( dispatch_time ( DISPATCH_TIME_NOW , ( int64_t )( 5 * NSEC_PER_SEC )), dispatch_get_main_queue (), ^{
        [subject
sendNext : @"myword" ];
        [subject
sendCompleted ];
    });
   
   
return subject;
}
    [[ self importPhotos ] subscribeNext :^( id x) {
       
NSLog ( @"x1 == %@" ,x);
    }];

    [[
self importPhotos ] subscribeNext :^( id x) {
       
NSLog ( @"x2 == %@" ,x);
    }];
2015-06-05 14:58:52.344 DemoCategorizer[19469:2329348] x1 == myword
2015-06-05 14:58:52.345 DemoCategorizer[19469:2329348] x2 == myword
注意两次时间几乎是一样的,原因在于RACReplaySubject把最后一次执行结果保存了下来.

array
取出长度大于3的字符串,再组成一个array
    NSArray *result = [[[[ @[ @"aaaa" , @"bb" , @"ccc" , @"dd" , @"ffffff" ] rac_sequence ] filter :^ BOOL ( id value) {
       
return [value length ] > 3 ;
    }]
map :^ id ( id value) {
       
return value;
    }]
array ];
   
    NSLog(@"result = %@",result);



timeout
    RACSignal *signal =
    [
RACSignal createSignal :^ RACDisposable *( id < RACSubscriber > subscriber) {
       
       
RACDisposable *disposable = [ RACDisposable new ];
       
       
dispatch_async ( dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 ), ^{
           
NSLog ( @"Start iterating..." );
           
for ( int i = 0 ; i < 200 && !disposable. isDisposed ; i++) {
               
NSLog ( @"Send %i to subscriber" , i);
                [subscriber
sendNext : @( i ) ];
               
                [
NSThread sleepForTimeInterval : 0.1 ];
            }
           
           
if (!disposable. isDisposed ) {
               
NSLog ( @"Send completed to subscriber" );
                [subscriber
sendCompleted ];
            }
        });
       
       
return disposable;
    }];
   
   
NSLog ( @"About to subscribe" );
   
    [[[signal
      
deliverOn :[ RACScheduler mainThreadScheduler ]]
     
timeout : 1.0 onScheduler :[ RACScheduler mainThreadScheduler ]]
    
subscribeNext :^( id x) {
        
NSLog ( @"Got next: %@" , x);
     }
error :^( NSError *error) {
        
NSLog ( @"Error (timeout): %@" , [error localizedDescription ]);
     }
completed :^{
        
NSLog ( @"Completed" );
     }];
如果在1秒钟之内没有收到sendCompleted,那么timeout将会发送一个error出来.参考 http://spin.atomicobject.com/2014/09/25/timeouts-in-reactivecocoa/




@weakify(self);

RACSignal *enabled = [[RACObserve(self, viewModels)
   
// Map _each_ array of view models to a signal determining whether the command
   
// should be enabled.
   
map:^(NSArray *viewModels) {
       
RACSequence *selectionSignals = [[viewModels.rac_sequence
           
map:^(ViewModel *viewModel) {
               
// RACObserve() implicitly retains `self`, so we need to avoid
               
// a retain cycle.
               
@strongify(self);

               
// Observe each view model's `isSelected` property for changes.
               
return RACObserve(viewModel, isSelected);
           
}]
           
// Ensure we always have one YES for the -and below.
            startWith
:[RACSignal return:@YES]];

       
// Sends YES whenever all of the view models are selected, NO otherwise.
       
return [[RACSignal
            combineLatest
:selectionSignals]
            and
];
   
}]
   
// Then, ensure that we only subscribe to the _latest_ signal returned from
   
// the block above (i.e., the observations from the latest `viewModels`).
    switchToLatest
];

观察NSArray里所有对象里的一个Bool变量




倒数计时3秒,再开始录音10秒
    __block NSInteger second = 3 ;
   
RACSignal *timer = [[[ RACSignal interval : 1 onScheduler :[ RACScheduler mainThreadScheduler ]] take : 3 ] map :^ id ( id value) {
       
NSLog ( @"ready time = %ld" ,second--);
       
return @YES ;
    }];
   
RACSignal *record = [ RACSignal createSignal :^ RACDisposable *( id < RACSubscriber > subscriber) {
       
DDLogDebug ( @"start recording." );
       
RACSignal *signal = [[ RACSignal interval : 1 onScheduler :[ RACScheduler mainThreadScheduler ]] take : 10 ];
       
RACDisposable *disposable = [signal subscribeNext :^( id x) {
           
NSLog ( @"recording sec %ld" ,second++);
            [subscriber
sendNext :x];
           
        }
completed :^{
           
NSLog ( @"record completed." );
            [subscriber
sendCompleted ];
        }];
       
       
return disposable;
    }];
   
RACSignal *chianSignal =  [timer concat :record];
   
    [chianSignal
subscribeNext :^( id x) {
       
NSLog ( @"x = %@" ,x);
    }
completed :^{
       
NSLog ( @"all done" );
    }];


// - ( RACSignal *)initially:( void (^)( void ))block
///   // Write new file, with backup.
///   [[[[fileManager
///       rac_createFileAtPath:path contents:data]
///       initially:^{
///           // 2. Second, backup current file
///           [fileManager moveItemAtPath:path toPath:backupPath error:nil];
///       }]
///       initially:^{
///           // 1. First, acquire write lock.
///           [writeLock lock];
///       }]
///       finally:^{
///           [writeLock unlock];
///       }];


// - ( RACSignal *)bufferWithTime:( NSTimeInterval )interval onScheduler:( RACScheduler *)scheduler
当single要在很短的时候内吐出N个value, bufferWithTime可以以interval的间隔分割它们.
它确保了每interval时间内,只收到一次next,value为期间的所有的内容tuple


//-replay 总是收取最后的内容,而并不执行signal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
  __block int num = 0;
  RACSignal *signal = [[RACSignal createSignal:^RACDisposable *(id  subscriber) {
      num++;
      NSLog(@"Increment num to: %i", num);
      [subscriber sendNext:@(num)];
      return nil;
  }] replay];
 
  NSLog(@"Start subscriptions");
 
  // Subscriber 1 (S1)
  [signal subscribeNext:^(id x) {
      NSLog(@"S1: %@", x);
  }];
 
  // Subscriber 2 (S2)
  [signal subscribeNext:^(id x) {
      NSLog(@"S2: %@", x);
  }];
 
  // Subscriber 3 (S3)
  [signal subscribeNext:^(id x) {
      NSLog(@"S3: %@", x);
  }];
  Increment num to: 1
  Start subscriptions
  S1: 1
  S2: 1
  S3: 1
-replay  总是取出第一订阅者取到的 所有结果
-replayLast 总是取出第一个订阅者取到的 最后一个结果
-replayLazily有点说不上来
replayLazily does not subscribe to the signal immediately – it lazily waits until there is a “real” subscriber. But replay subscribes immediately. So as you point out, with replayLazily the “A” value would not be sent to subscribers of the signal because it was sent before there was anything listening.


- ( RACSignal *)aggregateWithStartFactory:( id (^)( void ))startFactory reduce:( id (^)( id running, id next))reduceBlock
- ( RACSignal *)aggregateWithStart:( id )start reduce:( id (^)( id running, id next))reduceBlock
- ( RACSignal *)aggregateWithStart:( id )start reduceWithIndex:( id (^)( id , id , NSUInteger ))reduceBlock 

这三个货的作用,收到signal发送过来的next值,通过reduce
    RACSequence *seq = [ @"a b c d e f" componentsSeparatedByString : @" " ]. rac_sequence ;
    [[seq.
signal aggregateWithStart :[ NSMutableSet set ] reduce :^ id ( id running, id next) {
       
NSLog ( @"running = %@, next = %@" ,running,next);
       
NSString *newString = [next stringByAppendingString :next];
        [running
addObject :newString];
       
return running;
    }]
subscribeNext :^( id x) {
       
NSLog ( @"x = %@" ,x);
    }
completed :^{
       
NSLog ( @"completed" );
    }];
output:
2015-07-09 16:19:42.556 DemoCategorizer[74923:2050916] running = {(
)}, next = a
2015-07-09 16:19:42.556 DemoCategorizer[74923:2050916] running = {(
    aa
)}, next = b
2015-07-09 16:19:42.557 DemoCategorizer[74923:2050916] running = {(
    aa,
    bb
)}, next = c
2015-07-09 16:19:42.557 DemoCategorizer[74923:2050916] running = {(
    cc,
    aa,
    bb
)}, next = d
2015-07-09 16:19:42.557 DemoCategorizer[74923:2050916] running = {(
    cc,
    dd,
    aa,
    bb
)}, next = e
2015-07-09 16:19:42.557 DemoCategorizer[74923:2050916] running = {(
    cc,
    dd,
    aa,
    ee,
    bb
)}, next = f
2015-07-09 16:19:42.557 DemoCategorizer[74923:2050916] x = {(
    cc,
    dd,
    aa,
    ee,
    bb,
    ff
)}
2015-07-09 16:19:42.557 DemoCategorizer[74923:2050916] completed
直到set遍历完所有的值,最后由next吐出来

//throttle
    RACSignal *s2 = [[ RACSignal interval : 5 onScheduler :[ RACScheduler mainThreadScheduler ]] map :^ id ( id value) {
       
return @"s2" ;
    }];
   
   
RACSignal *s3 = [s2 throttle : 3 ]; //3 秒钟之内 , 没有第二个 sendNext, s3 sendNext
    [s3
subscribeNext :^( id x) {
       
NSLog ( @"%@" ,x);
    }];
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值