RAC的API
信号类:有数据产生的时候
RACSignal;
实质 RACDynamicSignal -> didSubscribe(block)
RACSubject -> subscribers(数组)
RACReplaySubject -> valuesReceived(数组)
不同的信号订阅方式不同
RACDynamicSignal: 1.创建订阅者 RACSubscriber 2.执行didSubscribe
RACSubject:1.创建订阅者 RACSubscriber 2.保存订阅者
RACReplaySubject: 1.创建订阅者 RACSubscriber 2.拿到当前创建的订阅者,发送之前保存的所有值
订阅者:发送数据 执行nextBlock
RACSubscriber
RACSubject
RACReplaySubject
信号触发结构
A 初始化信号内容;B 信号订阅;C 信号发送回调;D 信号发送
A createSignal后挂block(不触发任何操作)
B subscribeNext(触发A)
C subscribeNext后挂block(不触发任何操作)
D sendNext(触发C)
B->A,D->C,我们常将D写在A里构成 B->A->D->C;
炒饭模式具体实现
1.createSignal
创建 RACDynamicSignal* 传入 didSubscribe(block)
2.subscribeNext
初始化一个RACSubscriber*,并把 订阅回调block赋给RACSubscriber* ->next
实现 RACDynamicSignal* subscribe: 包含订阅回调block的订阅者(RACSubscriber*)
初始化一个RACPassthroughSubscriber*,->innerSubscriber *传入RACSubscriber*,->signal*传入RACDynamicSignal*,当信号的didSubscribe不为空时 进行某些判断后 执行didSubscribe并将RACPassthroughSubscriber* 当做参数传入
3.sendNext:value
取RACPassthroughSubscriber*->innerSubscriber 执行 sendNext
RACSubscriber*执行next(value)方法,next为订阅回调block
平台模式具体实现
1.createSignal
创建 RACDynamicSignal* 传入 didSubscribe(block)
2.[RACDynamicSignal* publish];
创建一个RACMulticastConnection对象,把RACDynamicSignal*传给 ->sourceSignal,初始化一个RACSubject*传给 ->signal;
3.[connection.signal subscribeNext:^(id _Nullablex) { }];
初始化一个RACSubscriber*,并把 订阅回调block赋给->next
实现 RACSubject* subscribe: 包含订阅回调block的订阅者(RACSubscriber*)
初始化一个RACPassthroughSubscriber*,->innerSubscriber *传入RACSubscriber*,->signal*传入RACSubject*。
将RACPassthroughSubscriber*添加到RACSubject*->subscribers里。
4.[connection connect];
RACMulticastConnection*的sourceSignal属性执行 [RACDynamicSignal* subscribe:RACSubject*]
初始化一个RACPassthroughSubscriber*,->innerSubscriber *传入传入RACSubject*,->signal*传入RACSubject*,当信号的didSubscribe不为空时 进行某些判断后 执行didSubscribe并将RACPassthroughSubscriber* 当做参数传入
5.sendNext:value
遍历RACSubject*->subscribers 取subscriber 分别执行 sendNext
RACSubscriber*执行next(value)方法,next为订阅回调block
不同订阅者,发送信号的方式不同
[RACSubscriber sendNext] : 执行nextBlock
[RACSubject sendNext] : 遍历自身subscribers,让他们执行nextBlock
[RACReplaySubject sendNext] : 1.保存发送的值 2.遍历父类RACSubject的subscribers,让他们执行nextBlock
rac常用的宏
1.RAC(self.name_lb,text)=self.name_tf.rac_textSignal;
将前一个属性绑定为后一个属性,当后一个属性发生变化时自动同步给前一个属性。
2.[RACObserve(self,self.name)subscribeNext:^(id _Nullablex) {}];
监听一个属性,每当这个属性发生变化时执行block;
3.@weakify(_name);@strongify(_name);
弱引用/强引用
4.RACTuple*tuple=RACTuplePack(@10,@"name");
将一个数据集合包装成元组;
5.selfrac_liftSelector:@selector(updateUI:data:)withSignals:hotSignal,newSignal,nil];
类线程组操作,当所有信号发送完毕后执行@selector,形参依此为信号数据。
raccommand
RACCOMMAND执行顺序:
[commandexecute:@123];
SignalBlock();
command.executionSignals.next();
signalBlock返回的信号的didSubscribe();
内部connection.signal.next();
bind:
- (RACSignal *)bind:(RACSignalBindBlock (^)(void))block;
此方法的参数是一个以 RACSignalBindBlock()为返回的block;
此方法返回一个信号racSingal_A;
此方法的执行就是创造返回结果信号,将block_N传给didSubscribe()。
didSubscribe()将在racSingal_A.subscribeNext:时触发:
racSingal_A.subscribeNext
1.定义block
1)completeSignal()(忽略) 2)addSignal() (addSignal(racSingal_B);为racSingal_B添加subscribeNext:block_Y();
blockY:调用racSingal_A的sendNext)
2.将block()运行并获取返回值RACSignalBindBlock();
3.为当前bind方法的调用者添加subscribeNext:block_X();
(block_X实现:触发RACSignalBindBlock(x)并获得返回信号racSingal_B;
x为bind调用者的实参;)
subject.sendnext(x)
subject.sendnext(x)->subject.block_X(x)->RACSignalBindBlock(X)(中转暴露,可修改传参)->racSingal_B=[RACReturnSignal return:value];->addSignal(racSingal_B)->[racSingal_B subscribeNext:block_Y() error:nil completed:nil]-> [RACReturnSignal subscribe:o]->[subscriber sendNext:self.value];->racSingal_B.next()->racSingal_A.sendNext
bindflattenMap:
他内部其实就是实现了一个bind,flatten的block与内部bind的入参跟返回完全一样,同样没做处理。所以他的功能就是bind的功能。
map:
他内部其实就是实现了一个flattenMap,map:的入参是一个(id(^)(idvalue))block类型,map方法把这个block的返回值id处理成当前信号类类型并把处理过的block传进flattenMap入参,省掉了使用者在block中封装信号的代码。
组合:
concat:通过concat:函数连接两个信号,将生成一个新信号,订阅新信号会立即触发信号1的
- (RACDisposable*)subscribeNext:(void(^)(idx))nextBlock error:(void(^)(NSError*error))errorBlock completed:(void(^)(void))completedBlock;
为信号1的订阅者生成 nextBlock,errorBlock,completedBlock;
继而调用信号1的didSubscribe(subscriber);
若信号1didSubscribe中有sendnext:则触发信号1的nextblock();继而触发新信号的nextblock;
信号1的订阅者调用sendCompleted方法时,会调用completedBlock(),触发信号2调用subscribe:,传参为信号1的订阅者,此时调用信号2的didSubscribe(subscriber),
若信号2didSubscribe中有sendnext:则触发信号1的nextblock();继而触发新信号的nextblock;
then:内部封装的concat:通过filter:^(id_) {
return NO;
}返回A flattenMap: empty block的新信号,新信号由于addSignal()入参为空导致新信号subscriber.sendnext()不能被触发;
现象,第一个信号不返回,只返回第二个信号;
merge:本质上还是利用了bind:
merge:返回组合信号的bind值,以下称信号fA&B,组合信号称信号A&B;
订阅 fA&B 时,触发bind内部的self subscribeNext: A&B订阅,触发merge:中的遍历,传参subscriber为 A&B的订阅者,依此触发[subscriber sendNext: signal];执行bind中A&B的nextBlock,传入子信号A或B,执行addSignal(signal),为子信号订阅事件 [subscriber sendNext:x];(即fA&B发送信号),此时,当子信号发送消息时,fA&B可以响应。
zipWith:这个最简单,zipwith:返回新信号,新信号被订阅时生成sendCompletedIfNecessary与sendNext的 block,同时两个原始信号被订阅,订阅逻辑都是数组添加信号返回值,并通过sendNext()判断是否两个信号都有返回,若都返回,则新信号发送消息,结果为两信号的元组。
combineLatest:reduce:这个不太想写细节了,主要是用combineLatest组合成返回元组的新信号(combineLatestWith:订阅每个原始信号以监听),然后在reduceEach:中绑定传入的block使每次调用都触发;
其他API:
filter:
此方法返回一个入参为bool类型,返回新信号,当满足bool条件时,才会收到信号内容。
ignore:
此方法输入一个发送值,或者输入ignoreValues,生成新信号,表示新信号会忽略输入的发送值发送;
take:
此方法输入数字,表示新生成的信号发送次数上限,超过次数的发送会被忽略;
takeLast:
此方法输入数字,表示新生成信号最后几次的值会被正常发送,前面发送的值会被发送,需要与sendCompleted一起使用;
takeUntil:
此方法输入一个信号,当输入信号sendCompleted或发送过一次后,新信号将忽略旧信号发送值;
distinctUntilChanged
当旧信号发送的值与上一次相异时,新信号才能收到值;
skip:
此方法输入数字,表示新生成信号会跳过旧信号前几次发送的值;