美文网首页
RAC-基础笔记

RAC-基础笔记

作者: 小小厨师 | 来源:发表于2018-05-04 14:56 被阅读82次

    文章优先发布于小小厨师的厨房

    RAC最主要的优势在于提供了一种统一的方式来处理异步行为,包括delegate、回调block、target-action机制、通知和KVO。

    RACStream

    RAC的核心,一个抽象类,RAC中的信号都继承自这个类。其本身不是非常有用,大部分由signalssequences代替。
    其中定义了一系列流操作的方法,实现在子类中重写。
    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,但是不允许重新排序或相互依赖。
    除了+immediateSchedulerScheduler不允许同步执行。

    生成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}
    

    推荐阅读

    细说ReactiveCocoa的冷信号与热信号

    iOS函数响应式编程以及ReactiveCocoa的使用

    Draveness's Blog

    相关文章

      网友评论

          本文标题:RAC-基础笔记

          本文链接:https://www.haomeiwen.com/subject/xbmdrftx.html