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

bind

flattenMap:

他内部其实就是实现了一个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:

此方法输入数字,表示新生成信号会跳过旧信号前几次发送的值;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,723评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,080评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,604评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,440评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,431评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,499评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,893评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,541评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,751评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,547评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,619评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,320评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,890评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,896评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,137评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,796评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,335评论 2 342

推荐阅读更多精彩内容