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的用法(这个吧是杀关键的靶子)等等。如果把这些操作比作武器的话,可能再次着重的凡内功,也便是懂外的琢磨,我们怎样通过实战,知道适当的以他的强硬,慢慢的习和深切是趟到渠道成的事情。

相关文章