RAC-基礎(chǔ)筆記

文章優(yōu)先發(fā)布于小小廚師的廚房

RAC最主要的優(yōu)勢(shì)在于提供了一種統(tǒng)一的方式來(lái)處理異步行為存筏,包括delegate、回調(diào)block、target-action機(jī)制唁影、通知和KVO。

RACStream

RAC的核心掂名,一個(gè)抽象類据沈,RAC中的信號(hào)都繼承自這個(gè)類。其本身不是非常有用饺蔑,大部分由signalssequences代替锌介。
其中定義了一系列流操作的方法,實(shí)現(xiàn)在子類中重寫猾警。
Stream表示一系列對(duì)象的值孔祸,值可在現(xiàn)在或?qū)?lái)可用,但都是依次檢索的发皿。

RACSignal

繼承自RACStream崔慧,一種push-driven的流。通常用來(lái)表示將在未來(lái)傳遞的數(shù)據(jù)穴墅。
冷信號(hào)惶室,當(dāng)訂閱的時(shí)候才發(fā)送消息。當(dāng)多次訂閱玄货,信號(hào)體內(nèi)代碼將會(huì)多次執(zhí)行皇钞。
任何的信號(hào)轉(zhuǎn)換即是對(duì)原有的信號(hào)進(jìn)行訂閱從而產(chǎn)生新的信號(hào)

創(chuàng)建信號(hào)

    // 創(chuàng)建信號(hào)
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        [subscriber sendNext:@"發(fā)送信號(hào)"];
        [subscriber sendCompleted];
        // 錯(cuò)誤和結(jié)束發(fā)送只能二選一
        // [subscriber sendError:[NSError errorWithDomain:@"RACDemo" code:110 userInfo:@{NSLocalizedDescriptionKey : @"錯(cuò)誤"}]];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"-------------->disposable");
        }];
    }];

訂閱信號(hào)

    // 訂閱信號(hào)
    [signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->第一次訂閱:%@", x);
    }];

RACSubject

即能充當(dāng)信號(hào),也能發(fā)送信號(hào)松捉,是一個(gè)可以手動(dòng)控制的信號(hào)夹界。
熱信號(hào),即使未訂閱也會(huì)發(fā)送信號(hào)隘世。當(dāng)訂閱信號(hào)后可柿,只會(huì)收到訂閱時(shí)間之后的信號(hào)。
RACSubject實(shí)現(xiàn)了RACSubscriber協(xié)議丙者。

@protocol RACSubscriber <NSObject>
@required
- (void)sendNext:(nullable id)value;
- (void)sendError:(nullable NSError *)error;
- (void)sendCompleted;
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;

@end

RACSubject有兩個(gè)子類:

  • RACReplaySubject:保存發(fā)送值的信號(hào)复斥,保存的值數(shù)量由設(shè)置的容量決定。當(dāng)有新的訂閱者蔓钟,將會(huì)將保存的值重發(fā)永票。
  • RACBehaviorSubject:會(huì)重發(fā)訂閱之前的最后一個(gè)值。

RACSubject:

    RACSubject *subject = [RACSubject subject];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->RACSubject1:%@",x);
    }];
    [subject sendNext:@"B"];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->RACSubject2:%@",x);
    }];
    [subject sendNext:@"C"];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->RACSubject3:%@",x);
    }];
    [subject sendNext:@"D"];

打印:

2018-01-23 17:48:07.697511+0800 RACLoginDemo[66964:32709151] -------------->RACSubject1:B
2018-01-23 17:48:07.697702+0800 RACLoginDemo[66964:32709151] -------------->RACSubject1:C
2018-01-23 17:48:07.697823+0800 RACLoginDemo[66964:32709151] -------------->RACSubject2:C
2018-01-23 17:48:07.697947+0800 RACLoginDemo[66964:32709151] -------------->RACSubject1:D
2018-01-23 17:48:07.698232+0800 RACLoginDemo[66964:32709151] -------------->RACSubject2:D
2018-01-23 17:48:07.698401+0800 RACLoginDemo[66964:32709151] -------------->RACSubject3:D

RACReplaySubject:

    RACReplaySubject *subject = [RACReplaySubject subject];
    [subject sendNext:@"A"];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->RACReplaySubject1:%@",x);
    }];
    [subject sendNext:@"B"];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->RACReplaySubject2:%@",x);
    }];
    [subject sendNext:@"C"];
    [subject subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->RACReplaySubject3:%@",x);
    }];
    [subject sendNext:@"D"];

打勇录:

2018-01-23 17:51:26.818273+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject1:A
2018-01-23 17:51:26.818514+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject1:B
2018-01-23 17:51:26.818648+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject2:A
2018-01-23 17:51:26.818806+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject2:B
2018-01-23 17:51:26.818958+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject1:C
2018-01-23 17:51:26.819078+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject2:C
2018-01-23 17:51:26.819276+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject3:A
2018-01-23 17:51:26.819377+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject3:B
2018-01-23 17:51:26.819482+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject3:C
2018-01-23 17:51:26.819677+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject1:D
2018-01-23 17:51:26.819795+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject2:D
2018-01-23 17:51:26.820147+0800 RACLoginDemo[67096:32734184] -------------->RACReplaySubject3:D

RACBehaviorSubject:

    RACBehaviorSubject *sub = [RACBehaviorSubject behaviorSubjectWithDefaultValue:@"init"];
    [sub subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->RACBehaviorSubject1:%@",x);
    }];
    [sub sendNext:@"A"];
    [sub sendNext:@"B"];
    
    [sub subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->RACBehaviorSubject2:%@",x);
    }];
    [sub sendNext:@"C"];

打蛹恪:

2018-01-23 17:53:35.242953+0800 RACLoginDemo[67192:32750779] -------------->RACBehaviorSubject1:init
2018-01-23 17:53:35.243233+0800 RACLoginDemo[67192:32750779] -------------->RACBehaviorSubject1:A
2018-01-23 17:53:35.243373+0800 RACLoginDemo[67192:32750779] -------------->RACBehaviorSubject1:B
2018-01-23 17:53:35.243570+0800 RACLoginDemo[67192:32750779] -------------->RACBehaviorSubject2:B
2018-01-23 17:53:35.243721+0800 RACLoginDemo[67192:32750779] -------------->RACBehaviorSubject1:C
2018-01-23 17:53:35.243831+0800 RACLoginDemo[67192:32750779] -------------->RACBehaviorSubject2:C

RACMulticastConnection

RACMulticastConnection用于將冷信號(hào)轉(zhuǎn)換為熱信號(hào),用于多播。connection避免直接創(chuàng)建世分,可以通過(guò)RACSignal-publish或者-multicast:創(chuàng)建编振。
-publish內(nèi)部實(shí)現(xiàn):

- (RACMulticastConnection *)publish {
    RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name];
    RACMulticastConnection *connection = [self multicast:subject];
    return connection;
}

使用publish方法,在connect后訂閱的訂閱者不能收到消息臭埋。
eg:

    static NSInteger sendCount = 0;
    RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
        NSString *temp = [NSString stringWithFormat:@"----->發(fā)送信號(hào):%ld",++sendCount];
        NSLog(@"%@",temp);
        [subscriber sendNext:temp];
        [subscriber sendCompleted];
        // 錯(cuò)誤和結(jié)束發(fā)送只能二選一
        // [subscriber sendError:[NSError errorWithDomain:@"RACDemo" code:110 userInfo:@{NSLocalizedDescriptionKey : @"錯(cuò)誤"}]];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"-------------->disposable");
        }];
    }];
    RACMulticastConnection *connection = [signal publish];
    // 訂閱信號(hào)
    [connection.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->第一次訂閱:%@", x);
    }];
    
    [connection.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->第二次訂閱:%@", x);
    }];
    [connection connect];
    [connection.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->第三次訂閱:%@", x);
    }];

打幼傺搿:

2018-01-25 17:50:54.061115+0800 RACLoginDemo[64455:5028191] ----->發(fā)送信號(hào):1
2018-01-25 17:50:54.061328+0800 RACLoginDemo[64455:5028191] -------------->第一次訂閱:----->發(fā)送信號(hào):1
2018-01-25 17:50:54.061457+0800 RACLoginDemo[64455:5028191] -------------->第二次訂閱:----->發(fā)送信號(hào):1
2018-01-25 17:50:54.061693+0800 RACLoginDemo[64455:5028191] -------------->disposable

如果需要connect之后的訂閱者也能收到消息,可以使用RACReplaySubject瓢阴。
eg:

    省略代碼....
    RACReplaySubject *subject = [RACReplaySubject subject];
    RACMulticastConnection *connection = [signal multicast:subject];
    省略代碼....

如果有這樣的需求可以通過(guò)更簡(jiǎn)單的方法實(shí)現(xiàn),RACSignal提供了三個(gè)更便利的方法:

/// Multicasts the signal to a RACReplaySubject of unlimited capacity, and
/// immediately connects to the resulting RACMulticastConnection.
///
/// Returns the connected, multicasted signal.
- (RACSignal<ValueType> *)replay;

/// Multicasts the signal to a RACReplaySubject of capacity 1, and immediately
/// connects to the resulting RACMulticastConnection.
///
/// Returns the connected, multicasted signal.
- (RACSignal<ValueType> *)replayLast;

/// Multicasts the signal to a RACReplaySubject of unlimited capacity, and
/// lazily connects to the resulting RACMulticastConnection.
///
/// This means the returned signal will subscribe to the multicasted signal only
/// when the former receives its first subscription.
///
/// Returns the lazily connected, multicasted signal.
- (RACSignal<ValueType> *)replayLazily;

RACCommand

繼承自NSObject畅蹂,創(chuàng)建并訂閱信號(hào)以響應(yīng)某個(gè)動(dòng)作∪倏郑可以結(jié)合UIControl一起使用液斜。

初始化

初始化1:

- (instancetype)initWithEnabled:(nullable RACSignal<NSNumber *> *)enabledSignal signalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;

初始化2:多傳入的enableSignal為nil。

- (instancetype)initWithSignalBlock:(RACSignal<ValueType> * (^)(InputType _Nullable input))signalBlock;

eg:

    RACCommand *command = [[RACCommand alloc] initWithSignalBlock:^RACSignal * _Nonnull(id  _Nullable input) {
        return [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
            // 可以用來(lái)封裝網(wǎng)絡(luò)請(qǐng)求叠穆。
            // 如果不sendCompleted將不會(huì)再相應(yīng)
            NSLog(@"-------------->RACSignal:%@",input);
            [subscriber sendNext:input];
            [subscriber sendCompleted];
            return [RACDisposable disposableWithBlock:^{
                NSLog(@"-------------->disposable");
            }];
        }];
    }];
    [[command.executionSignals switchToLatest] subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->getData:%@",x);
    }];
    [command execute:@"inputData"];

打由倨帷:

2018-01-25 16:56:34.138045+0800 RACLoginDemo[63214:4720098] -------------->RACSignal:inputData
2018-01-25 16:56:34.138297+0800 RACLoginDemo[63214:4720098] -------------->getData:inputData
2018-01-25 16:56:34.138650+0800 RACLoginDemo[63214:4720098] -------------->disposable

RACSequence

繼承自RACStream,一種pull-driven的流硼被。Sepuence是一種集合示损,不過(guò)其中的數(shù)據(jù)只有當(dāng)其使用時(shí)才加載。RAC為大部分Cocoa的集合添加了-rac_sequence方法嚷硫,以便轉(zhuǎn)化為RACSequence使用检访。
eg:

    RACSequence *results = [[@[@"1",@"22",@"333"].rac_sequence
                             filter:^ BOOL (NSString *str) {
                                 return str.length >= 2;
                             }]
                            map:^(NSString *str) {
                                NSLog(@"-------------->x:%@",str);
                                return [str stringByAppendingString:@"foobar"];
                            }];
    [results.signal subscribeNext:^(id  _Nullable x) {
        NSLog(@"-------------->result:%@",x);
    }];
    NSArray *array = results.array;
    NSLog(@"-------------->array:%@",array);

打印:

2018-01-26 11:38:20.317264+0800 RACLoginDemo[68540:5938859] -------------->x:22
2018-01-26 11:38:20.317512+0800 RACLoginDemo[68540:5938859] -------------->result:22foobar
2018-01-26 11:38:20.317523+0800 RACLoginDemo[68540:5938681] -------------->x:333
2018-01-26 11:38:20.317706+0800 RACLoginDemo[68540:5938859] -------------->result:333foobar
2018-01-26 11:38:20.317771+0800 RACLoginDemo[68540:5938681] -------------->array:(
    22foobar,
    333foobar
)

RACScheduler

RACScheduler類表示的調(diào)度程序是一個(gè)串行隊(duì)列论巍,用于執(zhí)行工作或傳遞結(jié)果信號(hào)烛谊。
調(diào)度程序類似于GCD,但是通過(guò)disposables可以取消嘉汰。也類似于NSOperationQueue,但是不允許重新排序或相互依賴。
除了+immediateScheduler状勤,Scheduler不允許同步執(zhí)行鞋怀。

生成Scheduler

+ (RACScheduler *)immediateScheduler;:立即執(zhí)行閉包里的任務(wù),同步執(zhí)行持搜。
+ (RACScheduler *)mainThreadScheduler;:主線程中執(zhí)行密似。
+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority name:(nullable NSString *)name:異步線程,指定線程優(yōu)先級(jí)和名字葫盼。
+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority;:異步線程残腌,指定線程優(yōu)先級(jí),名稱默認(rèn)。
+ (RACScheduler *)scheduler;:異步線程抛猫,默認(rèn)優(yōu)先級(jí)和名稱蟆盹。
+ (nullable RACScheduler *)currentScheduler;:當(dāng)前線程。當(dāng)在主線程或在-[RACScheduler schedule:]的block中才會(huì)執(zhí)行闺金。
eg:

    NSLog(@"-------------->currentThread:%@",[NSThread currentThread]);
    [[RACScheduler immediateScheduler] schedule:^{
        NSLog(@"-------------->immediateThread1:%@",[NSThread currentThread]);
    }];
    [[RACScheduler mainThreadScheduler] schedule:^{
        NSLog(@"-------------->mainThreadSchedulerThread2:%@",[NSThread currentThread]);
    }];
    [[RACScheduler schedulerWithPriority:RACSchedulerPriorityHigh] schedule:^{
        NSLog(@"-------------->PriorityThread3:%@",[NSThread currentThread]);
    }];

    [[RACScheduler scheduler] schedule:^{
        NSLog(@"-------------->schedulerThread4:%@",[NSThread currentThread]);
    }];
    [[RACScheduler currentScheduler] schedule:^{
        NSLog(@"-------------->currentSchedulerThread5:%@",[NSThread currentThread]);
    }];

打佑饫摹:

2018-01-26 14:42:24.483686+0800 RACLoginDemo[75856:6897026] -------------->currentThread:<NSThread: 0x60000027ba80>{number = 4, name = (null)}
2018-01-26 14:42:24.484447+0800 RACLoginDemo[75856:6897026] -------------->immediateThread1:<NSThread: 0x60000027ba80>{number = 4, name = (null)}
2018-01-26 14:42:24.484919+0800 RACLoginDemo[75856:6897026] -------------->currentSchedulerThread5:<NSThread: 0x60000027ba80>{number = 4, name = (null)}
2018-01-26 14:42:24.484992+0800 RACLoginDemo[75856:6897022] -------------->PriorityThread3:<NSThread: 0x600000272140>{number = 3, name = (null)}
2018-01-26 14:42:24.485163+0800 RACLoginDemo[75856:6897038] -------------->schedulerThread4:<NSThread: 0x60000027bc00>{number = 5, name = (null)}
2018-01-26 14:42:24.489472+0800 RACLoginDemo[75856:6896563] -------------->mainThreadSchedulerThread2:<NSThread: 0x60000007cc40>{number = 1, name = main}

推薦閱讀

細(xì)說(shuō)ReactiveCocoa的冷信號(hào)與熱信號(hào)

iOS函數(shù)響應(yīng)式編程以及ReactiveCocoa的使用

Draveness's Blog

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市败匹,隨后出現(xiàn)的幾起案子寨昙,更是在濱河造成了極大的恐慌,老刑警劉巖掀亩,帶你破解...
    沈念sama閱讀 219,188評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舔哪,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡槽棍,警方通過(guò)查閱死者的電腦和手機(jī)捉蚤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)刹泄,“玉大人外里,你說(shuō)我怎么就攤上這事√厥” “怎么了盅蝗?”我有些...
    開(kāi)封第一講書人閱讀 165,562評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)姆蘸。 經(jīng)常有香客問(wèn)我墩莫,道長(zhǎng),這世上最難降的妖魔是什么逞敷? 我笑而不...
    開(kāi)封第一講書人閱讀 58,893評(píng)論 1 295
  • 正文 為了忘掉前任狂秦,我火速辦了婚禮,結(jié)果婚禮上推捐,老公的妹妹穿的比我還像新娘裂问。我一直安慰自己,他們只是感情好牛柒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布堪簿。 她就那樣靜靜地躺著,像睡著了一般皮壁。 火紅的嫁衣襯著肌膚如雪椭更。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,708評(píng)論 1 305
  • 那天蛾魄,我揣著相機(jī)與錄音虑瀑,去河邊找鬼湿滓。 笑死,一個(gè)胖子當(dāng)著我的面吹牛舌狗,可吹牛的內(nèi)容都是我干的叽奥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,430評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼把夸,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼而线!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起恋日,我...
    開(kāi)封第一講書人閱讀 39,342評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤膀篮,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后岂膳,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體誓竿,經(jīng)...
    沈念sama閱讀 45,801評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評(píng)論 3 337
  • 正文 我和宋清朗相戀三年谈截,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了筷屡。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,115評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡簸喂,死狀恐怖毙死,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情喻鳄,我是刑警寧澤扼倘,帶...
    沈念sama閱讀 35,804評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站除呵,受9級(jí)特大地震影響再菊,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜颜曾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評(píng)論 3 331
  • 文/蒙蒙 一纠拔、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泛豪,春花似錦稠诲、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,008評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至岗仑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間聚请,已是汗流浹背荠雕。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,135評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工稳其, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人炸卑。 一個(gè)月前我還...
    沈念sama閱讀 48,365評(píng)論 3 373
  • 正文 我出身青樓既鞠,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親盖文。 傳聞我的和親對(duì)象是個(gè)殘疾皇子嘱蛋,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容