RAC基础学习一:信号与订阅者模式。ReactiveCocoa 中 RACSignal 是怎样发送信号的。

俺们当明到RAC的有力以及不可思议的时刻,需要想两单地方:1、它是怎么样贯彻之?第二单问题则重复发生难度:2、它是哪想到这么设计的?
这边我们事先品尝研究第一个问题,它是何许贯彻的,分析重点的系统。

原文:《掘金专栏 – ReactiveCocoa 中 RACSignal
是怎样发送信号的》
作者:
同详实殇流化隐半边冰霜

当RAC里面,我们具备围绕的事物只主体是随即几乎类:信号(signal)、订阅者(subscriber)、还有关于信号的劳动者实体、信号的客,这几独之干。
咱怎么用RAC,因为其解耦太好了,除此之外,它简洁,配合MVVM能发挥出很挺之来意等等。相信我们都写腻了对象期间的繁杂通信、一生堆状态的创办及治本、越来越难以保障的事务逻辑,这些就是是RAC诞生之沉重。

章都由此作者授权。

乍家总是容易让同样堆放概念将得晕头转向,我想实在只有是马上几种:

前言

ReactiveCocoa大凡一个(第一个?)将函数响应式编程范例带入Objective-C的开源库。ReactiveCocoa是由Josh
Abernathy和Justin
Spahr-Summers
两位生神以针对GitHub for
Mac的支出过程中编的。Justin
Spahr-Summers
大神以2011年11月13号下午12接触35细分进行的第一糟糕提交,直到2013年2月13日上午3点05分披露了该1.0
release,达到了第一单基本点里程碑。ReactiveCocoa社区为酷活跃,目前流行版本曾成功了ReactiveCocoa
5.0.0-alpha.3,目前在5.0.0-alpha.4出被。

ReactiveCocoa v2.5
是公认的Objective-C最平稳的本,因此深受广泛的以OC为重大语言的客户端选中动用。ReactiveCocoa
v3.x主要是因Swift 1.2底版本,而ReactiveCocoa v4.x 主要基于Swift
2.x,ReactiveCocoa 5.0尽管全面支持Swift 3.0,也许还有以后的Swift
4.0。接下来几首博客先盖ReactiveCocoa
v2.5版本也例子,分析一下OC版的RAC具体贯彻(也许分析了了RAC
5.0纵赶来了)。也终究写于ReactiveCocoa 5.0规范版来前夕的祝福吧。

RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber){
            [subscriber sendNext:@(1)];
            [subscriber sendCompleted];
            return nil;
        }];

目录

  • 1.什么是ReactiveCocoa?
  • 2.RAC挨的核心RACSignal发送和订阅流程
  • 3.RACSignal操作的核心bind实现
  • 4.RACSignal基本操作concat和zipWith实现
  • 5.最后

  1、createSignal好难啊;2、subscriber是呀?3、这个block什么时调用?

一. 什么是ReactiveCocoa?

ReactiveCocoa(其简称为RAC)是出于Github
开源之一个行使叫iOS和OS
X开发之新框架。RAC有函数式编程(FP)和响应式编程(RP)的风味。它主要吸取了.Net的
Reactive
Extensions的筹划和促成。

ReactiveCocoa 的主旨是Streams of values over time
,随着岁月变化而持续流淌的数据流。

ReactiveCocoa 主要解决了以下这些题目:

  • UI数据绑定

UI控件便需绑定一个风波,RAC可以好有利的绑定任何数据流到控件上。

  • 用户交互事件绑定

RAC也而互相的UI控件提供了千篇一律文山会海能够发送Signal信号的章程。这些多少流会在用户交互中互相传递。

  • 化解状态与状态之间因过多之题目

起了RAC的绑定后,可以无用当关心各种复杂的状态,isSelect,isFinish……也化解了这些状态在深很不便保障的问题。

  • 消息传递机制的深集合

OC中编程原来消息传递机制有以下几栽:Delegate,Block
Callback,Target-Action,Timers,KVO,objc上发出雷同篇有关OC中即5种消息传递方式转什么抉择的稿子Communication
Patterns,推荐大家读。现在生了RAC之后,以上这5栽艺术都得合用RAC来处理。

[signal subscribeNext:^(id x) {
        if ([x boolValue]) {
            _navView.hidden = YES;
        } else {
            _navView.hidden = NO;
            [UIView animateWithDuration:.5 animations:^{
                _navView.alpha = 1;
            }];
        }
    }];

二. RAC中之核心RACSignal

ReactiveCocoa
中最好核心之概念有就是是信号RACStream。RACRACStream中出些许个子类——RACSignal
和 RACSequence。本文先来分析RACSignal。

俺们会常看看以下的代码:

RACSignal *signal = [RACSignal createSignal:
                     ^RACDisposable *(id<RACSubscriber> subscriber)
{
    [subscriber sendNext:@1];
    [subscriber sendNext:@2];
    [subscriber sendNext:@3];
    [subscriber sendCompleted];
    return [RACDisposable disposableWithBlock:^{
        NSLog(@"signal dispose");
    }];
}];
RACDisposable *disposable = [signal subscribeNext:^(id x) {
    NSLog(@"subscribe value = %@", x);
} error:^(NSError *error) {
    NSLog(@"error: %@", error);
} completed:^{
    NSLog(@"completed");
}];

[disposable dispose];

及时是一个RACSignal被订阅的完好过程。被订阅的经过中,究竟出了哟?

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
 return [RACDynamicSignal createSignal:didSubscribe];
}

RACSignal调用createSignal的时候,会调用RACDynamicSignal的createSignal的方法。

图片 1

RACDynamicSignal是RACSignal的子类。createSignal后面的参数是一个block。

(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe

block的返回值是RACDisposable类型,block名叫didSubscribe。block的唯一一个参数是id<RACSubscriber>类型的subscriber,这个subscriber是得遵循RACSubscriber协议的。

RACSubscriber是一个商事,其下发生以下4只商量章程:

@protocol RACSubscriber <NSObject>
@required

- (void)sendNext:(id)value;
- (void)sendError:(NSError *)error;
- (void)sendCompleted;
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;

@end

因而新建Signal的任务便合赢得于了RACSignal的子类RACDynamicSignal上了。

@interface RACDynamicSignal ()
// The block to invoke for each subscriber.
@property (nonatomic, copy, readonly) RACDisposable * (^didSubscribe)(id<RACSubscriber> subscriber);
@end

RACDynamicSignal这个类似非常粗略,里面就是保存了一个名叫didSubscribe的block。

+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
     RACDynamicSignal *signal = [[self alloc] init];
     signal->_didSubscribe = [didSubscribe copy];
     return [signal setNameWithFormat:@"+createSignal:"];
}

其一措施吃新建了一个RACDynamicSignal对象signal,并把染上的didSubscribe这个block保存进刚刚新建对象signal里面的didSubscribe属性中。最后更受signal命名+createSignal:。

- (instancetype)setNameWithFormat:(NSString *)format, ... {
 if (getenv("RAC_DEBUG_SIGNAL_NAMES") == NULL) return self;

   NSCParameterAssert(format != nil);

   va_list args;
   va_start(args, format);

   NSString *str = [[NSString alloc] initWithFormat:format arguments:args];
   va_end(args);

   self.name = str;
   return self;
}

setNameWithFormat是RACStream里面的不二法门,由于RACDynamicSignal继承自RACSignal,所以她吗会调用这个法。

图片 2

RACSignal的block就如此让保存起来了,那什么时会于执行为?

图片 3

block闭包在订阅的下才会为“释放”出来。

RACSignal调用subscribeNext方法,返回一个RACDisposable。

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock {
   NSCParameterAssert(nextBlock != NULL);
   NSCParameterAssert(errorBlock != NULL);
   NSCParameterAssert(completedBlock != NULL);

   RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:errorBlock completed:completedBlock];
   return [self subscribe:o];
}

于这艺术被见面新建一个RACSubscriber对象,并传nextBlock,errorBlock,completedBlock。

@interface RACSubscriber ()

// These callbacks should only be accessed while synchronized on self.
@property (nonatomic, copy) void (^next)(id value);
@property (nonatomic, copy) void (^error)(NSError *error);
@property (nonatomic, copy) void (^completed)(void);
@property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;

@end

RACSubscriber这个类似非常简单,里面就来4只特性,分别是nextBlock,errorBlock,completedBlock和一个RACCompoundDisposable信号。

+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
 RACSubscriber *subscriber = [[self alloc] init];

   subscriber->_next = [next copy];
   subscriber->_error = [error copy];
   subscriber->_completed = [completed copy];

   return subscriber;
}

图片 4

subscriberWithNext方法把传播的3只block都保留分别保存至好相应之block中。

RACSignal调用subscribeNext方法,最后return的时候,会调用[self
subscribe:o],这里其实是调用了RACDynamicSignal类里面的subscribe方法。

- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
 NSCParameterAssert(subscriber != nil);

   RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
   subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];

   if (self.didSubscribe != NULL) {
      RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
      RACDisposable *innerDisposable = self.didSubscribe(subscriber);
      [disposable addDisposable:innerDisposable];
  }];

    [disposable addDisposable:schedulingDisposable];
 }

 return disposable;
}

RACDisposable有3只子类,其中一个就是是RACCompoundDisposable。

图片 5

@interface RACCompoundDisposable : RACDisposable
+ (instancetype)compoundDisposable;
+ (instancetype)compoundDisposableWithDisposables:(NSArray *)disposables;
- (void)addDisposable:(RACDisposable *)disposable;
- (void)removeDisposable:(RACDisposable *)disposable;
@end

RACCompoundDisposable虽然是RACDisposable的子类,但是它们里面可以参加多只RACDisposable对象,在必要之时节可以一口气且调用dispose方法来销毁信号。当RACCompoundDisposable对象吃dispose的上,也会见活动dispose容器内的有RACDisposable对象。

RACPassthroughSubscriber是一个个体的类。

@interface RACPassthroughSubscriber : NSObject <RACSubscriber>
@property (nonatomic, strong, readonly) id<RACSubscriber> innerSubscriber;
@property (nonatomic, unsafe_unretained, readonly) RACSignal *signal;
@property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;
- (instancetype)initWithSubscriber:(id<RACSubscriber>)subscriber signal:(RACSignal *)signal disposable:(RACCompoundDisposable *)disposable;
@end

RACPassthroughSubscriber类就只有这一个措施。目的就是是以拿富有的信号事件由一个订阅者subscriber传递给任何一个尚尚未disposed的订阅者subscriber。

RACPassthroughSubscriber类中保存了3个非常主要之目标,RACSubscriber,RACSignal,RACCompoundDisposable。RACSubscriber是急需转发的信号的订阅者subscriber。RACCompoundDisposable是订阅者的销毁对象,一旦她让disposed了,innerSubscriber就再度为接受不顶事件流了。

此需要小心的凡里面还保留了一个RACSignal,并且它们的性质是unsafe_unretained。这里和任何两单特性有分,
其他两独属性都是strong的。这里用不是weak,是坐引用RACSignal仅仅只是一个DTrace
probes动态跟踪技术之探针。如果设置成weak,会导致没必要之性损失。所以这边就是unsafe_unretained就够了。

- (instancetype)initWithSubscriber:(id<RACSubscriber>)subscriber signal:(RACSignal *)signal disposable:(RACCompoundDisposable *)disposable {
   NSCParameterAssert(subscriber != nil);

   self = [super init];
   if (self == nil) return nil;

   _innerSubscriber = subscriber;
   _signal = signal;
   _disposable = disposable;

   [self.innerSubscriber didSubscribeWithDisposable:self.disposable];
   return self;
}

回到RACDynamicSignal类里面的subscribe方法吃,现在新建好了RACCompoundDisposable和RACPassthroughSubscriber对象了。

 if (self.didSubscribe != NULL) {
  RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
   RACDisposable *innerDisposable = self.didSubscribe(subscriber);
   [disposable addDisposable:innerDisposable];
  }];

  [disposable addDisposable:schedulingDisposable];
 }

RACScheduler.subscriptionScheduler是一个大局的单例。

+ (instancetype)subscriptionScheduler {
   static dispatch_once_t onceToken;
   static RACScheduler *subscriptionScheduler;
   dispatch_once(&onceToken, ^{
    subscriptionScheduler = [[RACSubscriptionScheduler alloc] init];
   });

   return subscriptionScheduler;
}

RACScheduler再持续调整用schedule方法。

- (RACDisposable *)schedule:(void (^)(void))block {
   NSCParameterAssert(block != NULL);
   if (RACScheduler.currentScheduler == nil) return [self.backgroundScheduler schedule:block];
   block();
   return nil;
}


+ (BOOL)isOnMainThread {
 return [NSOperationQueue.currentQueue isEqual:NSOperationQueue.mainQueue] || [NSThread isMainThread];
}

+ (instancetype)currentScheduler {
 RACScheduler *scheduler = NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey];
 if (scheduler != nil) return scheduler;
 if ([self.class isOnMainThread]) return RACScheduler.mainThreadScheduler;

 return nil;
}

于取currentScheduler的经过被,会判定currentScheduler是否存在,和是否当主线程中。如果还没有,那么尽管会见调用后台backgroundScheduler去实施schedule。

schedule的入参就是一个block,执行schedule的下会失掉执行block。也就是会见失去履行:

RACDisposable *innerDisposable = self.didSubscribe(subscriber);
   [disposable addDisposable:innerDisposable];

马上片句子关键之语句。之前信号中保存的block就会见于此地被“释放”执行。self.didSubscribe(subscriber)这无异于句子就实行了信号保存之didSubscribe闭包。

在didSubscribe闭包着发出sendNext,sendError,sendCompleted,执行这些语句会分别调用RACPassthroughSubscriber里面对应之法子。

- (void)sendNext:(id)value {
 if (self.disposable.disposed) return;
 if (RACSIGNAL_NEXT_ENABLED()) {
  RACSIGNAL_NEXT(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString([value description]));
 }
 [self.innerSubscriber sendNext:value];
}

- (void)sendError:(NSError *)error {
 if (self.disposable.disposed) return;
 if (RACSIGNAL_ERROR_ENABLED()) {
  RACSIGNAL_ERROR(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString(error.description));
 }
 [self.innerSubscriber sendError:error];
}

- (void)sendCompleted {
 if (self.disposable.disposed) return;
 if (RACSIGNAL_COMPLETED_ENABLED()) {
  RACSIGNAL_COMPLETED(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description));
 }
 [self.innerSubscriber sendCompleted];
}

这时节的订阅者是RACPassthroughSubscriber。RACPassthroughSubscriber里面的innerSubscriber才是终极之莫过于订阅者,RACPassthroughSubscriber会把价值更持续传递让innerSubscriber。

- (void)sendNext:(id)value {
 @synchronized (self) {
  void (^nextBlock)(id) = [self.next copy];
  if (nextBlock == nil) return;

  nextBlock(value);
 }
}

- (void)sendError:(NSError *)e {
 @synchronized (self) {
  void (^errorBlock)(NSError *) = [self.error copy];
  [self.disposable dispose];

  if (errorBlock == nil) return;
  errorBlock(e);
 }
}

- (void)sendCompleted {
 @synchronized (self) {
  void (^completedBlock)(void) = [self.completed copy];
  [self.disposable dispose];

  if (completedBlock == nil) return;
  completedBlock();
 }
}

innerSubscriber是RACSubscriber,调用sendNext的时刻会事先管自己之self.next闭包copy一客,再调用,而且全过程或者线程安全的,用@synchronized保护着。最终订阅者的闭包在此地让调用。

sendError和sendCompleted也都是同理。

小结一下:

图片 6

  1. RACSignal调用subscribeNext方法,新建一个RACSubscriber。
  2. 新建的RACSubscriber会copy,nextBlock,errorBlock,completedBlock存在好的性能变量中。
  3. RACSignal的子类RACDynamicSignal调用subscribe方法。
  4. 新建RACCompoundDisposable和RACPassthroughSubscriber对象。RACPassthroughSubscriber分别保存对RACSignal,RACSubscriber,RACCompoundDisposable的援,注意对RACSignal的援是unsafe_unretained的。
  5. RACDynamicSignal调用didSubscribe闭包。先调用RACPassthroughSubscriber的照应的sendNext,sendError,sendCompleted方法。
  6. RACPassthroughSubscriber再错过调用self.innerSubscriber,即RACSubscriber的nextBlock,errorBlock,completedBlock。注意这里调用同样是先copy一份,再调用闭包执行。

  4、subscribeNext又是呀?5、这个block什么时调用?

三. RACSignal操作的核心bind实现

图片 7

当RACSignal的源码里面富含了点滴单基本操作,concat和zipWith。不过当条分缕析这点儿单操作前,先来分析一下更为核心之一个函数,bind操作。

先行来说说bind函数的用意:

  1. 会晤订阅原始之信号。
  2. 任何时刻原始信号发送一个值,都见面绑定的block转换一糟。
  3. 若果绑定的block转换了价值变成信号,就马上订阅,并把价值发给订阅者subscriber。
  4. 假设绑定的block要停下绑定,原始之信号就complete。
  5. 当有的信号还complete,发送completed信号于订阅者subscriber。
  6. 而中途信号出现了任何error,都设拿这个荒唐发送给subscriber

- (RACSignal *)bind:(RACStreamBindBlock (^)(void))block {
 NSCParameterAssert(block != NULL);

 return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
  RACStreamBindBlock bindingBlock = block();

  NSMutableArray *signals = [NSMutableArray arrayWithObject:self];

  RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];

  void (^completeSignal)(RACSignal *, RACDisposable *) = ^(RACSignal *signal, RACDisposable *finishedDisposable) { /*这里暂时省略*/ };
  void (^addSignal)(RACSignal *) = ^(RACSignal *signal) { /*这里暂时省略*/ };

  @autoreleasepool {
   RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init];
   [compoundDisposable addDisposable:selfDisposable];

   RACDisposable *bindingDisposable = [self subscribeNext:^(id x) {
    // Manually check disposal to handle synchronous errors.
    if (compoundDisposable.disposed) return;

    BOOL stop = NO;
    id signal = bindingBlock(x, &stop);

    @autoreleasepool {
     if (signal != nil) addSignal(signal);
     if (signal == nil || stop) {
      [selfDisposable dispose];
      completeSignal(self, selfDisposable);
     }
    }
   } error:^(NSError *error) {
    [compoundDisposable dispose];
    [subscriber sendError:error];
   } completed:^{
    @autoreleasepool {
     completeSignal(self, selfDisposable);
    }
   }];

   selfDisposable.disposable = bindingDisposable;
  }

  return compoundDisposable;
 }] setNameWithFormat:@"[%@] -bind:", self.name];
}

为弄清楚bind函数究竟开了啊,写有测试代码:

    RACSignal *signal = [RACSignal createSignal:
                         ^RACDisposable *(id<RACSubscriber> subscriber)
    {
        [subscriber sendNext:@1];
        [subscriber sendNext:@2];
        [subscriber sendNext:@3];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signal dispose");
        }];
    }];

    RACSignal *bindSignal = [signal bind:^RACStreamBindBlock{
        return ^RACSignal *(NSNumber *value, BOOL *stop){
            value = @(value.integerValue * 2);
            return [RACSignal return:value];
        };
    }];

    [bindSignal subscribeNext:^(id x) {
        NSLog(@"subscribe value = %@", x);
    }];

出于前第一章节节详细讲解了RACSignal的创始与订阅的全经过,这个邪为艺术教,创建RACDynamicSignal,RACCompoundDisposable,RACPassthroughSubscriber这些都有点过,这里根本分析一下bind之逐一闭包传递创建同订阅的过程。

以防接下的解析会吃读者看晕,这里先管要就此到的block进行编号。

    RACSignal *signal = [RACSignal createSignal:
                         ^RACDisposable *(id<RACSubscriber> subscriber)
    {
        // block 1
    }

    RACSignal *bindSignal = [signal bind:^RACStreamBindBlock{
        // block 2
        return ^RACSignal *(NSNumber *value, BOOL *stop){
            // block 3
        };
    }];

    [bindSignal subscribeNext:^(id x) {
        // block 4
    }];

- (RACSignal *)bind:(RACStreamBindBlock (^)(void))block {
        // block 5
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        // block 6
        RACStreamBindBlock bindingBlock = block();
        NSMutableArray *signals = [NSMutableArray arrayWithObject:self];

        void (^completeSignal)(RACSignal *, RACDisposable *) = ^(RACSignal *signal, RACDisposable *finishedDisposable) {
        // block 7
        };

        void (^addSignal)(RACSignal *) = ^(RACSignal *signal) {
        // block 8
            RACDisposable *disposable = [signal subscribeNext:^(id x) {
            // block 9
            }];
        };

        @autoreleasepool {
            RACDisposable *bindingDisposable = [self subscribeNext:^(id x) {
                // block 10
                id signal = bindingBlock(x, &stop);

                @autoreleasepool {
                    if (signal != nil) addSignal(signal);
                    if (signal == nil || stop) {
                        [selfDisposable dispose];
                        completeSignal(self, selfDisposable);
                    }
                }
            } error:^(NSError *error) {
                [compoundDisposable dispose];
                [subscriber sendError:error];
            } completed:^{
                @autoreleasepool {
                    completeSignal(self, selfDisposable);
                }
            }];
        }
        return compoundDisposable;
    }] ;
}

预先创造信号signal,didSubscribe把block1 copy保存起来。

当信号调用bind进行绑定,会调用block5,didSubscribe把block6
copy保存起来。

当订阅者开始订阅bindSignal的时,流程如下:

  1. bindSignal执行didSubscribe的block,即执行block6。
  2. 于block6 的率先句代码,就是调用RACStreamBindBlock bindingBlock =
    block(),这里的block是外传上的block2,于是起调用block2。执行完block2,会回一个RACStreamBindBlock的靶子。
  3. 由是signal调用的bind函数,所以bind函数里面的self就是signal,在bind内部订阅了signal的信号。subscribeNext所以会履block1。
  4. 尽block1,sendNext调用订阅者subscriber的nextBlock,于是起履行block10。
  5. block10备受见面先行调用bindingBlock,这个是事先调用block2的归来值,这个RACStreamBindBlock对象中保存的是block3。所以开始调用block3。
  6. 每当block3中可参是一个value,这个value是signal中sendNext中作出去的value的价值,在block3惨遭得本着value进行换,变换完成后,返回一个初的信号signal’。
  7. 若是回到的signal’为空,则会调用completeSignal,即调用block7。block7中会发送sendCompleted。如果回到的signal’不呢空,则会调用addSignal,即调用block8。block8中会连续订阅signal’。执行block9。
  8. block9
    中见面sendNext,这里的subscriber是block6的入参,于是对subscriber调用sendNext,会调用到bindSignal的订阅者的block4中。
  9. block9
    中推行完sendNext,还会调用sendCompleted。这里的是当履block9里面的completed闭包。completeSignal(signal,
    selfDisposable);然后又会调用completeSignal,即block7。
  10. 推行完block7,就完事了同潮打signal 发送信号sendNext的净经过。

bind整个流程就做到了。

  6、看起上面两段子代码有涉及,但是具体怎么打算的?

四. RACSignal基本操作concat和zipWith实现

连着下去再来分析RACSignal中另外2独基本操作。

为我们先行来缓解者的迷离吧!

1. concat

图片 8

写来测试代码:

    RACSignal *signal = [RACSignal createSignal:
                         ^RACDisposable *(id<RACSubscriber> subscriber)
    {
        [subscriber sendNext:@1];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signal dispose");
        }];
    }];


    RACSignal *signals = [RACSignal createSignal:
                         ^RACDisposable *(id<RACSubscriber> subscriber)
    {
        [subscriber sendNext:@2];
        [subscriber sendNext:@3];
        [subscriber sendNext:@6];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signal dispose");
        }];
    }];

    RACSignal *concatSignal = [signal concat:signals];

    [concatSignal subscribeNext:^(id x) {
        NSLog(@"subscribe value = %@", x);
    }];

concat操作就是将个别只信号合并起来。注意合并出先后顺序。

图片 9

- (RACSignal *)concat:(RACSignal *)signal {
   return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
    RACSerialDisposable *serialDisposable = [[RACSerialDisposable alloc] init];

    RACDisposable *sourceDisposable = [self subscribeNext:^(id x) {
     // 发送第一个信号的值
     [subscriber sendNext:x];
    } error:^(NSError *error) {
     [subscriber sendError:error];
    } completed:^{
     // 订阅第二个信号
     RACDisposable *concattedDisposable = [signal subscribe:subscriber];
     serialDisposable.disposable = concattedDisposable;
  }];

    serialDisposable.disposable = sourceDisposable;
    return serialDisposable;
 }] setNameWithFormat:@"[%@] -concat: %@", self.name, signal];
}

合前,signal和signals分别都把个别的didSubscribe保存copy起来。
合并后,合并之后新的信号的didSubscribe会把block保存copy起来。

当合并后的信号于订阅的时候:

  1. 调用新的联合信号的didSubscribe。
  2. 鉴于是第一只信号调用的concat方法,所以block中之self是前方一个信号signal。合并信号的didSubscribe会先订阅signal。
  3. 鉴于订阅了signal,于是起施行signal的didSubscribe,sendNext,sendError。
  4. 时一个信号signal发送sendCompleted之后,就会起来订阅后一个信号signals,调用signals的didSubscribe。
  5. 鉴于订阅了继一个信号,于是后一个信号signals开始发送sendNext,sendError,sendCompleted。

然少只信号就上下有序的拼接到了一块。

此出少数索要留意的凡,两个信号concat在一齐从此,新的信号的结束信号于其次单信号结束之时段才收。看上图描述,新的信号的殡葬长度等前面两个信号长度的同,concat之后的新信号的了断信号吗就算是第二独信号的竣工信号。

首先片 订阅者和信号##\

  1、隐藏的订阅者

  平时我们打交道的尽管是信号,但是连说订阅,却无明了订阅到底是怎进行的,也束手无策解答者的题材,让咱根据源码分析一下订阅过程。

  首先来认识一个目标:订阅者(RACSubscriber)。
订阅者订阅信号,就是如此简单的一模一样件工作。只不过框架隐藏了此目标,我们也不必要跟订阅者打交道,只待报告信号一样起事情,那便是要发送了数量(三种事件:next、complete、error),我们需要开啊事情(类似回调的概念)。

  第一步是创办信号,看一下方面的率先段落代码,createSignal类方法:
这里而说一下,信号RACSignal有局部子类,我们常常因此之是RACDynamicSignal和RACSubject,先不理会RACSubject。createSignal类方法创建的虽是RACDynamicSignal对象。

-----RACDynamicSignal.h-----
@property (nonatomic, copy, readonly) RACDisposable * (^didSubscribe)(id<RACSubscriber> subscriber);

-----RACSignal.m-----
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    return [RACDynamicSignal createSignal:didSubscribe];
}

-----RACDynamicSignal.m-----
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
    RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
    return [signal setNameWithFormat:@"+createSignal:"];
}

  我们可发现,RACDynamicSignal有一个特性,名字叫didSubscribe的block对象。createSignal方法传递的block参数,就是赋值给didSubscribe属性。
  对此问题1,我们得暂时这么对,createSignal的含义是,创建一个signal对象,并且把参数赋值给signal的称为也didSubscribe的性质,这个block的参数是subscriber,返回RACDisposable。

  第二步是订阅信号,看一下亚段落代码subscribeNext:

-----RACSubscriber.m-----
@property (nonatomic, copy) void (^next)(id value);

-----RACSignal.m-----
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);

    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [self subscribe:o];
}

-----RACDynamicSignal.m-----

- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);

    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];

    if (self.didSubscribe != NULL) {
        RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
            RACDisposable *innerDisposable = self.didSubscribe(subscriber);
            [disposable addDisposable:innerDisposable];
        }];

        [disposable addDisposable:schedulingDisposable];
    }

    return disposable;
}

  我们可见见,subscribeNext方法第一步是创建了一个RACSubscriber,也就是创立了一个订阅者,而且将subscribeNext的参数传递给RACSubscriber对象,RACSubscriber会把参数赋值给好一个称吧next的Block类型的性能,此地,我们可应对上面第4单问题,subscribeNext方法创建一个订阅者,并且将block参数,传递给订阅者一个名字叫next的性,block参数接收的是id类型,返回的是RACDisposable对象。接下去执行[self
subscribe:o],也便是订阅操作。我们当看望订阅方法subscribe的实现:上面的代码很清晰,直接是self.didSubscribe(subscriber),我们可理解,刚刚创建的subscriber对象,直接传送给上文中我们干的signal的didSubscribe属性。如此这般,我们得以分解上面的老二个跟老三单问题,subscriber就是didSubscribe的形参,block对象是当subscribeNext的时节实施的,刚刚的订阅者对象作为参数传入,就是subscriber对象。

  那么createSignal方法中,[subscriber sendNext:@(1)]是呀意思为?
  看一下sendNext方法吧:

- (void)sendNext:(id)value {
    @synchronized (self) {
        void (^nextBlock)(id) = [self.next copy];
        if (nextBlock == nil) return;

        nextBlock(value);
    }
}

  我们得以发现,sendNext的落实,也就是是直接实施上文中的nextBlock。也就算是答复了面第五单问题。

  总结一下,signal持有didSubscribe参数(createSignal传上的异常block),subscriber持有nextBlock(就是subscribeNext传上的不胜block),当行[signal
subscribe:subscriber]的时光,signal的didSubscribe执行,内部发生subscriber
sendNext的调用,触发了subscriber的nextBlock的调用。到这边,我们基本将信号和订阅者,以及订阅过程分析了。

2. zipWith

图片 10

写来测试代码:

    RACSignal *concatSignal = [signal zipWith:signals];

    [concatSignal subscribeNext:^(id x) {
        NSLog(@"subscribe value = %@", x);
    }];

图片 11

源码如下:

- (RACSignal *)zipWith:(RACSignal *)signal {
    NSCParameterAssert(signal != nil);

    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        __block BOOL selfCompleted = NO;
        NSMutableArray *selfValues = [NSMutableArray array];

        __block BOOL otherCompleted = NO;
        NSMutableArray *otherValues = [NSMutableArray array];

        void (^sendCompletedIfNecessary)(void) = ^{
            @synchronized (selfValues) {
                BOOL selfEmpty = (selfCompleted && selfValues.count == 0);
                BOOL otherEmpty = (otherCompleted && otherValues.count == 0);

                // 如果任意一个信号完成并且数组里面空了,就整个信号算完成
                if (selfEmpty || otherEmpty) [subscriber sendCompleted];
            }
        };

        void (^sendNext)(void) = ^{
            @synchronized (selfValues) {

                // 数组里面的空了就返回。
                if (selfValues.count == 0) return;
                if (otherValues.count == 0) return;

                // 每次都取出两个数组里面的第0位的值,打包成元组
                RACTuple *tuple = RACTuplePack(selfValues[0], otherValues[0]);
                [selfValues removeObjectAtIndex:0];
                [otherValues removeObjectAtIndex:0];

                // 把元组发送出去
                [subscriber sendNext:tuple];
                sendCompletedIfNecessary();
            }
        };

        // 订阅第一个信号
        RACDisposable *selfDisposable = [self subscribeNext:^(id x) {
            @synchronized (selfValues) {

                // 把第一个信号的值加入到数组中
                [selfValues addObject:x ?: RACTupleNil.tupleNil];
                sendNext();
            }
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            @synchronized (selfValues) {

                // 订阅完成时判断是否要发送完成信号
                selfCompleted = YES;
                sendCompletedIfNecessary();
            }
        }];

        // 订阅第二个信号
        RACDisposable *otherDisposable = [signal subscribeNext:^(id x) {
            @synchronized (selfValues) {

                // 把第二个信号加入到数组中
                [otherValues addObject:x ?: RACTupleNil.tupleNil];
                sendNext();
            }
        } error:^(NSError *error) {
            [subscriber sendError:error];
        } completed:^{
            @synchronized (selfValues) {

                // 订阅完成时判断是否要发送完成信号
                otherCompleted = YES;
                sendCompletedIfNecessary();
            }
        }];

        return [RACDisposable disposableWithBlock:^{

            // 销毁两个信号
            [selfDisposable dispose];
            [otherDisposable dispose];
        }];
    }] setNameWithFormat:@"[%@] -zipWith: %@", self.name, signal];
}

当把有限独信号通过zipWith之后,就如面的那么张图一律,拉链的个别度吃中的拉索拉到了旅。既然是拉链,那么一一底职位是产生照应的,上面的拉链第一单位置只能针对着下拉链第一单职位,这样牵连链才能够拉至手拉手去。

具体落实:

zipWith里面来有限只数组,分别会晤储存两单信号的价值。

  1. 苟订阅了zipWith之后的信号,就起来实践didSubscribe闭包。
  2. 以闭包中会优先订阅第一单信号。这里而第一独信号于第二单信号先有一个价值。第一独信号发出来的各个一个价值都见面让在到第一单数组中保存起来,然后调用sendNext(
    )闭包。在sendNext(
    )闭包中,会先判断两只数组里面是不是都也空,如果来一个数组里面凡是拖欠的,就return。由于第二只信号还尚未发送值,即第二单信号的数组里面凡是拖欠的,所以这里首先只价发送不下。于是第一单信号为订阅之后,发送的价存储到了第一只数组里面了,没有发下。
  3. 次单信号的值紧接着有来了,第二个信号每发送一不成值,也会蕴藏到第二单数组中,但是这个时节又调用sendNext(
    )闭包的时光,不见面再度return了,因为少单数组里面都发出价了,两单数组的第0哀号位置还出一个价了。有价后就起包成元组RACTuple发送出。并清空两只数组0声泪俱下位置存储的价。
  4. 日后少独信号每次发送一个,就先行囤于勤组吃,只要发生“配对”的另一个信号,就联合由包成元组RACTuple发送出。从图中也堪望,zipWith之后的新信号,每个信号的发送时刻是等两只信号最晚发出信号的时刻。
  5. 初信号的姣好时,是当彼此任意一个信号就而数组里面也空,就算完事了。所以最终第一个信号发送的5的酷值就是于废了。

率先只信号依次发送的1,2,3,4的价值与次独信号依次发送的A,B,C,D的值,一一的并在了一块儿,就比如拉链把她们拉在合。由于5没法配对,所以拉链也拉不上了。

仲有的 信号和波##\

  刚才咱们说了,signal有几单子类,每一个列的signal订阅过程实际上大同小异,而且最初常见的也罢就算是RACDynamicSignal,其实我们不需极度关注这题目,因为无论是从定义信号,还是框架定义的一对category,例如,textFiled的rac_textSignal属性,大多数都是RACDynamicSignal。另一个广泛的品类RACSubject可以下理解。

  还有即使是,我们恰好说到了三种植事件,分别是next、error、complete,和剖析next的订阅过程一样,举个例子,我们发送网络要,希望以阴差阳错的下,能吃用户提示,那么首先,创建信号的早晚,在网要失败的回调中,我们只要[subscriber
sendError:netError],也就是是发送错误事件。然后以订阅错误事件,也便是subscriberError:…这样就算到位了错误信号的订阅。

  complete事件于异常,它产生已订阅关系的代表,我们事先盖了解一下RACDispoable对象吧,我们解,订阅关系需出已之时候,比如,在tableViewCell的复用的时刻,cell会订阅model类产生一个信号,但是当cell被复用的上,如果无将前面的订阅关系取消掉,就会油然而生同时订阅了2只model的场面。我们得窥见,subscribeNext、subscribeError、subscribeComplete事件返回的都是RACDisopable对象,当我们盼望歇订阅的当儿,调用[RACDisposable
dispose]就足以了。complete也是是原理。

五. 最后

本来就篇文章纪念将Map,combineLatest,flattenMap,flatten这些也联合分析了,但是后来看来RACSingnal的操作实际有些多,于是以源码的文本分别了,这里先把RACSignal文件之中的操作都分析了了。RACSignal文件里的操作主要就bind,concat和zipWith三单操作。下一致首再分析分析RACSignal+Operations文件中的所有操作。

求大家多多指教。

老三片 进一步的深深##\

  RAC是一个分外大的框架,平时底一部分学科会误导大家纠结flattenMap和map的分别,这些题材,让人追寻不至头绪,导致入门更加的孤苦。实际上,学习她要一个循循渐进的进程,RAC有众多作用,解耦合,更迅速之解决一近似问题等等,总之,他是对准正规的面向对象编程很好的上。所以,在知晓了订阅的长河之后,重要之是,投入其实的运中,我观察了重重开源的路,并构成自己之行发现,其实flattenMap这样的操作,非常少,几乎从未,常用之光就是是以下几单:手动构建信号(createSignal)、订阅信号(subscribeNext)、使用框架的有些宏定义(RACObserve、RAC)、然后便是读书几单极度简易的操作,例如map、merge等就可以开始了。如果指望深入研讨,一定要是把这些基础之东西吃透,然后在就学又多之操作,例如flattenMap,了解side
effect和多播的定义,学会RACSubject的用法(这个为是可怜重要的目标)等等。如果管这些操作比作武器的话,可能重着重的凡内功,也尽管是掌握外的思量,我们什么通过实战,知道适当的运他的强,慢慢的熟悉与深入是水至渠道成的工作。

相关文章