文章優(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è)類。其本身不是非常有用饺蔑,大部分由signals
和sequences
代替锌介。
其中定義了一系列流操作的方法,實(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)