文章系列
《ReactiveCocoa 概述》
《RACSignal》
《RACDisposable》
《RACSubject快集、RACReplaySubject(內(nèi)附冷信號(hào)和熱信號(hào)的區(qū)別)》
《集合RACTuple、RACSequence》
《RAC 中的通知廉白、代理个初、KVO, 基本事件、方法的監(jiān)聽(tīng)》
《rac_liftSelector》
《RACMulticastConnection》
《RACCommand》
《RAC - 核心方法bind》
《RAC - 定時(shí)器》
《RACScheduler》
《RAC - 點(diǎn)擊獲取驗(yàn)證碼 demo》
《RAC - 映射(Map & flattenMap)》
《RAC信號(hào)操作解釋合集》
《RAC - 信號(hào)的生命周期》
- RACSubject
RACSignal 是冷信號(hào), 不能夠自己發(fā)送信號(hào), 需要訂閱者訂閱, 特點(diǎn)是
確定未來(lái), 也就是知道什么時(shí)候結(jié)束/終止, 無(wú)視訂閱者, 不管誰(shuí)訂閱, 都是從頭開(kāi)始執(zhí)行一段老代碼
幫助理解: 冷信號(hào) 相當(dāng)于 劇本, 當(dāng)訂閱者訂閱時(shí), 就相當(dāng)于開(kāi)始拍戲, 不管誰(shuí)訂閱, 都是從頭開(kāi)始拍, 拍完了也就結(jié)束了.
RACSubject
繼承自RACSignal
, 是熱信號(hào), 也就是說(shuō)既可以充當(dāng)信號(hào)猴蹂,也可以發(fā)送信號(hào), 并不確定什么時(shí)候終止, 關(guān)心訂閱者, 先來(lái)先得院溺、后來(lái)少得
幫助理解: 熱信號(hào) 相當(dāng)于 拍好的戲, 當(dāng)訂閱者訂閱時(shí), 就開(kāi)始演戲, 接下來(lái)再有訂閱者訂閱, 演到哪里就繼續(xù)演, 不會(huì)重新從頭開(kāi)始, 即先來(lái)的看得多、后來(lái)看的就少.
代碼分析:
// 1.創(chuàng)建信號(hào)
RACSubject *subject = [RACSubject subject];
// 2.訂閱信號(hào)
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"x = %@", x);
}];
// 3.發(fā)送數(shù)據(jù)
[subject sendNext:@10];
↓[RACSubject subject] 內(nèi)部實(shí)現(xiàn)↓
+ (instancetype)subject {
return [[self alloc] init];
}
- (instancetype)init {
self = [super init];
if (self == nil) return nil;
// 創(chuàng)建一個(gè) 復(fù)合的_disposable 對(duì)象, 用于取消訂閱
_disposable = [RACCompoundDisposable compoundDisposable];
// 創(chuàng)建一個(gè) _subscribers 訂閱者集合, 用來(lái)保存訂閱者
_subscribers = [[NSMutableArray alloc] initWithCapacity:1];
return self;
}
↓ 訂閱信號(hào) subscribeNext: 內(nèi)部實(shí)現(xiàn)↓
其實(shí)內(nèi)部也RACSignal 信號(hào)訂閱大致相同, 唯一不同的是subscribe: 方法的實(shí)現(xiàn):
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
NSMutableArray *subscribers = self.subscribers;
@synchronized (subscribers) {
// 注意: 每次訂閱, 都將訂閱者添加至 信號(hào)內(nèi)部的_subscribers 數(shù)組中
[subscribers addObject:subscriber];
}
[disposable addDisposable:[RACDisposable disposableWithBlock:^{
@synchronized (subscribers) {
// Since newer subscribers are generally shorter-lived, search
// starting from the end of the list.
NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id<RACSubscriber> obj, NSUInteger index, BOOL *stop) {
return obj == subscriber;
}];
if (index != NSNotFound) [subscribers removeObjectAtIndex:index];
}
}]];
return disposable;
}
↓ 發(fā)布消息sendNext: 內(nèi)部實(shí)現(xiàn)↓
- (void)sendNext:(id)value {
// 遍歷_subscribers 集合, 向每一個(gè)訂閱者發(fā)送sendNext: 消息, 即所有訂閱者依次發(fā)送消息
[self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
[subscriber sendNext:value];
}];
}
總結(jié)
- 創(chuàng)建的subject的是內(nèi)部會(huì)創(chuàng)建一個(gè)數(shù)組_subscribers用來(lái)保存所有的訂閱者
- 訂閱信息的時(shí)候會(huì)創(chuàng)建訂閱者磅轻,并且保存到數(shù)組中
- 遍歷subject中_subscribers中的訂閱者珍逸,依次發(fā)送信息
注意
RACSubject 可以被訂閱多次,并且只能是先訂閱后發(fā)布, 因?yàn)?
先發(fā)送, 再有訂閱者, 訂閱者收不到訂閱之前的消息, 所以稱(chēng)之為先來(lái)先得, 晚來(lái)少得
- RACReplaySubject
針對(duì)RACSubject 的注意點(diǎn), 偏偏要先發(fā)送消息, 再去訂閱信號(hào), 該怎么辦呢???
這里就可以使用RACReplaySubject ,
它繼承自RACSubject
, 目的就是來(lái)解決先發(fā)送信號(hào)后訂閱的問(wèn)題.
代碼分析: 和RACSubject 的使用一毛一樣
// 先發(fā)送信號(hào)
[replaySubject sendNext:@10];
// 后訂閱信號(hào)
[replaySubject subscribeNext:^(id _Nullable x) {
// 可以正常打印
NSLog(@"x = %@", x);
}];
↓具體實(shí)現(xiàn)原理↓
- RACReplaySubject 對(duì)象創(chuàng)建的時(shí)候, 會(huì)在父類(lèi)的基礎(chǔ)之上多做一步,創(chuàng)建一個(gè)數(shù)組用來(lái)保存發(fā)送的數(shù)據(jù)(當(dāng)_subscribers 中所有訂閱者都成功發(fā)送了數(shù)據(jù), 那么就會(huì)刪除當(dāng)前要發(fā)送的數(shù)據(jù), 避免出現(xiàn)一個(gè)數(shù)據(jù)重復(fù)發(fā)送的問(wèn)題)
- 發(fā)送數(shù)據(jù): 當(dāng)有訂閱者訂閱時(shí),發(fā)送數(shù)據(jù); 沒(méi)有訂閱者訂閱時(shí)發(fā)送失敗, 就不發(fā)送,等待新的訂閱者.
- 訂閱信號(hào), 先遍歷一次保存數(shù)據(jù)的數(shù)組, 如果有就執(zhí)行第二步
.End