RAC笔记

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

RACSignal *signal2 = [ *{
@"bbbb" @"hello222" ];
}];
*signal3 =[ combineLatest : @[ signal1,signal2 ] ];
[signal3 subscribeNext :^( id x) {
@"x = %@" ,x);
}];

//先处理signal2 再处理signal1,当两个信号都sendNext后,signal3才会触发
- ( *)zipwith:( *)signal
createSignal RACdisposable *( < RACSubscriber > subscriber) {
@"bbbbb" );
[subscriber
sendNext @"asdfasdf" ];
[subscriber
sendCompleted ];
return nil ;
}];

*signal3 = [signal2 zipwith :[signal1 logall ]];

[signal3
);
}
completed :^{
@"asdfasdfsdf" );
}];
// :与 zipwith :实际上结果是一样的.都是等到所有的signal被sendNext后,才会触发

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

RACSignal *signal1 = [ RACSignal defer :^ RACSignal *{
NSLog ( @"print signal1" );
return [ RACSignal return : @"signal1" ];
}];

RACSignal *signal2 = [ @"print signal2" );
@"signal2" ];
}];

RACSignal *signal3 = [signal1 concat :signal2];
[signal3
subscribeNext :^( id x) {
@"%@" ,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 .viewmodel,secCodeimageFile) skip 1 ] map :^ value) {
@"secCodeimageFile == %@" normal; font-family:Menlo; color:rgb(207,value);
[[ UIImage alloc ] initWithContentsOfFile :value];
// secCodeimageFile第一次为nil,可以通过skip跳过
//catch
/// Subscribes to the returned signal when an error occurs.
*)catch:(* (^)(NSError *error))catchBlock;

> subscriber) {
[subscriber
sendError :[ NSError errorWithDomain @"my fault" code 100 userInfo : nil ]];
RACdisposable disposableWithBlock @"done" );
}];
}];

*signal2 = [signal1 catch *( NSError *error) {
@"catch error" @"idiot" ];
}];

[signal2
}];
//catch用于,封装一个错误处理机制的signal,也就是当signal1出现了错误,将创建一个新的错误处理signal2,完成后并处理订阅者的流程
打个比方,如果要为服务器上某个商品点赞+1,但是出现了网络不同,此时,就要把UserDefault里的值减1.

/// Subscribes to the given signal when an error occurs.
*)catchTo:(*)signal;
catchTo @"my falut" ]];
[signal2

catch与 catchTo的目标是相同的,区别在于catch提供了一个处理error的机会,而catchTo直接无视error //try
*) try :( BOOL (^)( value, NSError **errorPtr))tryBlock;
*signal1 = [[ > subscriber) {
// 处理一个网络请求 , 当成功后把结果 okok 发送出去
[subscriber
@"okok" );
}];
}]
try ( Nsstring *s,209)"> * __autoreleasing *errorPtr) {
在这里尝试判断 signal 的结果 当收到了 Next 判断其值 如果结果与预期一样就 告诉订阅
比如网络请求的结果是对的
if ([s hasPrefix @"ok" ]) {
YES ;
}
else {
NO ;
}
}];

[signal1
id x) {
NSLog(@“subscribed.%@“,x //x == okok
}];
*)tryMap:( **errorPtr))mapBlock

try与tryMap都是为了判断一个signal是否sendNext,区别在于try可以根据结果来决定是否继续并且把kook发送给订阅方,而tryMap则会对值做一个转换再传给订阅
//delay
*)delay:( NSTimeInterval )interval
//sendNext后,再触发subscriber
//deliverOn
*)deliverOn:( RACScheduler *)scheduler
deliverOn RACScheduler scheduler ] //订阅者将在ReactiveCocoa创建的工作队列里收到sendNext
mainThreadScheduler //订阅者将在main thread创建的工作队列里收到sendNext
//if:then:else:
@NO @"hello222" *signal3 = [ @"cccc" @"hello333" ];
}];


[[
:signal1 then :signal2 else :signal3] id x) {
NSLog(@"subscribed. %@"//如果signal1sendNext:@YES,就执行signal2的内容,否则就是signal3
startWith:
RAC ( self .intervalTextField,text) = [[[ interval : 1 onScheduler :[ RACScheduler mainThreadScheduler ]] startWith : @"hello" ] map :^ id ( id value) {
Nsstring stringWithFormat : @"text %d" ,count++];
}];

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

RACAble/ RACAbleWithStart
反向绑定变量,当bindstring发生变化时,intervalTextField.text也会随着改变,但是反过来就不行
normal; font-family:Menlo; color:rgb(119,text) = RACAbleWithStart ( self .bindString);
RACAble 只是绑定, RACAbleWithStart是绑定后,立即对其赋值
merge/ combineLatest :
RACSignal *combinding = [ merge : @[self . textField1 . rac_textSignal , self . textField2 . rac_textSignal ] ];

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

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

[signal1
subscribeNext :^( id x) {
@"first %@" normal; font-family:Menlo; color:rgb(207,x);
}];

[signal1
@"second %@" }];
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
那么,我打算某个网络操作只做一次,然后多个订阅者都可以收到消息,怎么做?
@"signal1" ];
}];

RACMulticastConnection *connection = [signal1 publish ];
[connection.
signal subscribeNext @"first next value = %@" normal; font-family:Menlo; color:rgb(207,x);
}];

[connection.
@"second next value = %@" [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=[selfpopularURLRequest];

return[[[[[[NSURLConnectionrac_sendAsynchronousRequest:request]
reduceEach:^id(NSURLResponse*response,NSData*data){
returndata;
}]
deliverOn:[RACSchedulermainThreadScheduler]]
map:^id(NSData*data){
idresults=[NSJSONSerializationjsONObjectWithData:dataoptions:0error:nil];
return[[[results[@"photos"]rac_sequence]
map:^id(NSDictionary*photoDictionary){
FRPPhotoModel*model=[FRPPhotoModelnew];
[selfconfigurePhotoModel:modelwithDictionary:photoDictionary];
[selfdownloadThumbnailForPhotoModel:model];
returnmodel;
}]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 normal; font-family:Menlo; color:rgb(207,( int64_t )( 5 * NSEC_PER_SEC )), dispatch_get_main_queue (),^{
[subject
sendNext @"myword" ];
[subject
sendCompleted ];
});

return subject;
}
[[ self importPhotos ] @"x1 == %@" normal; font-family:Menlo; color:rgb(207,x);
}];

[[
@"x2 == %@" 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" normal; font-family:Menlo; color:rgb(207, @"bb" @"ccc" @"dd" @"ffffff" ] rac_sequence filter :^ BOOL ( value) {
[value length ] > 3 ;
}]
map value;
}]
array ];
@"result = %@"normal; color:rgb(207,result);

timeout
*signal =
[
createSignal RACdisposable *( < RACSubscriber > subscriber) {

RACdisposable *disposable = [ RACdisposable new ];

dispatch_async dispatch_get_global_queue disPATCH_QUEUE_PRIORITY_DEFAULT normal; font-family:Menlo; color:rgb(207, 0 ),^{
@"Start iterating..." for ( int i = ; i < 200 && !disposable. isdisposed ; i++) {
@"Send %i to subscriber" normal; font-family:Menlo; color:rgb(207,i);
[subscriber
: @( i ) ];

[
NSThread sleepForTimeInterval 0.1 ];
}

if (!disposable. ) {
@"Send completed to subscriber" );
[subscriber
];
}
});

disposable;
}];

@"About to subscribe" );

[[[signal
deliverOn :[ RACScheduler mainThreadScheduler ]]
timeout 1.0 onScheduler @"Got next: %@" normal; font-family:Menlo; color:rgb(207,x);
}
error :^( NSError *error) {
@"Error (timeout): %@" normal; font-family:Menlo; color:rgb(207,[error localizedDescription ]);
}
completed :^{
@"Completed" );
}];
如果在1秒钟之内没有收到sendCompleted,那么timeout将会发送一个error出来.参考 http://spin.atomicobject.com/2014/09/25/timeouts-in-reactivecocoa/

@weakify(self);

RACSignal*enabled=[[RACObserve,viewmodels)
//Map_each_arrayofviewmodelstoasignaldeterminingwhetherthecommand//shouldbeenabled.
map:^(NSArray{
RACSequenceselectionSignals[[.rac_sequence
viewmodelviewmodel
//RACObserve()implicitlyretains`self`,soweneedtoavoid //aretaincycle. @strongify

//Observeeachviewmodel's`isSelected`propertyforchanges.
returnisSelected
}]
//EnsurewealwayshaveoneYESforthe-andbelow.
startWith
:[return:@YES]];

//SendsYESwheneveralloftheviewmodelsareselected,NOotherwise.

combineLatest
:]
and
];
//Then,ensurethatweonlysubscribetothe_latest_signalreturnedfrom//theblockabove(i.e.,theobservationsfromthelatest`viewmodels`).
switchToLatest
];

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

倒数计时3秒,再开始录音10秒
__block NSInteger second = ;
RACSignal *timer = [[[ interval 1 ]] take value) {
@"ready time = %ld" normal; font-family:Menlo; color:rgb(207,second--);
return @YES ;
}];
*record = [ > subscriber) {
DDLogDebug @"start recording." );
*signal = [[ 10 ];
*disposable = [signal @"recording sec %ld" normal; font-family:Menlo; color:rgb(207,second++);
[subscriber
:x];

}
@"record completed." ];
}];

disposable;
}];
*chianSignal = [timer concat :record];

[chianSignal
@"x = %@" @"all done" }];
// *)initially:( 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]; /// }] /// // 1. First,acquire write lock. /// [writeLock lock]; /// finally:^{ /// [writeLock unlock];
/// }];

// *)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)
  "S2: %@",10)">// Subscriber 3 (S3)
  "S3: %@",0)">];
Incrementnumto:1
Startsubscriptions
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:( running, id next))reduceBlock
*)aggregateWithStart:( )start reduce:( )start reduceWithIndex:( normal; color:rgb(192, NSUInteger ))reduceBlock

这三个货的作用,收到signal发送过来的next值,通过reduce
RACSequence *seq = [ @"a b c d e f" componentsSeparatedByString : @" " ]. rac_sequence ;
[[seq.
signal aggregateWithStart :[ NSMutableSet set ] reduce :^ id ( normal; color:rgb(192, id next) {
NSLog ( @"running = %@,next = %@" normal; color:rgb(207,running,next);
Nsstring *newString = [next stringByAppendingString :next];
[running
addobject :newString];
return running;
}]
subscribeNext :^( x) {
@"x = %@" normal; color:rgb(207,x);
}
completed :^{
@"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,next = d
2015-07-09 16:19:42.557 DemoCategorizer[74923:2050916] running = {(
cc,
dd,next = e
2015-07-09 16:19:42.557 DemoCategorizer[74923:2050916] running = {(
cc,
ee,next = f
2015-07-09 16:19:42.557 DemoCategorizer[74923:2050916] x = {(
cc,
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 value) {
return @"s2" ;
}];

RACSignal *s3 = [s2 throttle 3 ]; //3 秒钟之内 normal; color:rgb(167, 没有第二个 sendNext,167)">即 s3 sendNext
[s3
@"%@" }];

相关文章

一、前言 在组件方面react和Vue一样的,核心思想玩的就是组件...
前言: 前段时间学习完react后,刚好就接到公司一个react项目...
前言: 最近收到组长通知我们项目组后面新开的项目准备统一技...
react 中的高阶组件主要是对于 hooks 之前的类组件来说的,如...
我们上一节了解了组件的更新机制,但是只是停留在表层上,例...
我们上一节了解了 react 的虚拟 dom 的格式,如何把虚拟 dom...