RAC-基础笔记
文章优先发布于小小厨师的厨房
RAC最主要的优势在于提供了一种统一的方式来处理异步行为,包括delegate、回调block、target-action机制、通知和KVO。
RACStream
RAC的核心,一个抽象类,RAC中的信号都继承自这个类。其本身不是非常有用,大部分由signals
和sequences
代替。
其中定义了一系列流操作的方法,实现在子类中重写。
Stream
表示一系列对象的值,值可在现在或将来可用,但都是依次检索的。
RACSignal
继承自RACStream
,一种push-driven的流。通常用来表示将在未来传递的数据。
冷信号,当订阅的时候才发送消息。当多次订阅,信号体内代码将会多次执行。
任何的信号转换即是对原有的信号进行订阅从而产生新的信号
创建信号
// 创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
[subscriber sendNext:@"发送信号"];
[subscriber sendCompleted];
// 错误和结束发送只能二选一
// [subscriber sendError:[NSError errorWithDomain:@"RACDemo" code:110 userInfo:@{NSLocalizedDescriptionKey : @"错误"}]];
return [RACDisposable disposableWithBlock:^{
NSLog(@"-------------->disposable");
}];
}];
订阅信号
// 订阅信号
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"-------------->第一次订阅:%@", x);
}];
RACSubject
即能充当信号,也能发送信号,是一个可以手动控制的信号。
热信号,即使未订阅也会发送信号。当订阅信号后,只会收到订阅时间之后的信号。
RACSubject
实现了RACSubscriber
协议。
@protocol RACSubscriber <NSObject>
@required
- (void)sendNext:(nullable id)value;
- (void)sendError:(nullable NSError *)error;
- (void)sendCompleted;
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;
@end
RACSubject
有两个子类:
-
RACReplaySubject
:保存发送值的信号,保存的值数量由设置的容量决定。当有新的订阅者,将会将保存的值重发。 -
RACBehaviorSubject
:会重发订阅之前的最后一个值。
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
用于将冷信号转换为热信号,用于多播。connection
避免直接创建,可以通过RACSignal
的-publish
或者-multicast:
创建。
-publish
内部实现:
- (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:@"----->发送信号:%ld",++sendCount];
NSLog(@"%@",temp);
[subscriber sendNext:temp];
[subscriber sendCompleted];
// 错误和结束发送只能二选一
// [subscriber sendError:[NSError errorWithDomain:@"RACDemo" code:110 userInfo:@{NSLocalizedDescriptionKey : @"错误"}]];
return [RACDisposable disposableWithBlock:^{
NSLog(@"-------------->disposable");
}];
}];
RACMulticastConnection *connection = [signal publish];
// 订阅信号
[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] ----->发送信号:1
2018-01-25 17:50:54.061328+0800 RACLoginDemo[64455:5028191] -------------->第一次订阅:----->发送信号:1
2018-01-25 17:50:54.061457+0800 RACLoginDemo[64455:5028191] -------------->第二次订阅:----->发送信号: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];
省略代码....
如果有这样的需求可以通过更简单的方法实现,RACSignal
提供了三个更便利的方法:
/// 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
,创建并订阅信号以响应某个动作。可以结合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) {
// 可以用来封装网络请求。
// 如果不sendCompleted将不会再相应
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
是一种集合,不过其中的数据只有当其使用时才加载。RAC为大部分Cocoa的集合添加了-rac_sequence
方法,以便转化为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
类表示的调度程序是一个串行队列,用于执行工作或传递结果信号。
调度程序类似于GCD
,但是通过disposables
可以取消。也类似于NSOperationQueue
,但是不允许重新排序或相互依赖。
除了+immediateScheduler
,Scheduler
不允许同步执行。
生成Scheduler
+ (RACScheduler *)immediateScheduler;
:立即执行闭包里的任务,同步执行。
+ (RACScheduler *)mainThreadScheduler;
:主线程中执行。
+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority name:(nullable NSString *)name
:异步线程,指定线程优先级和名字。
+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority;
:异步线程,指定线程优先级,名称默认。
+ (RACScheduler *)scheduler;
:异步线程,默认优先级和名称。
+ (nullable RACScheduler *)currentScheduler;
:当前线程。当在主线程或在-[RACScheduler schedule:]
的block中才会执行。
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}