RACSequence分析(一)

RACSequence 顾名思义就是序列,也就是存放一系列数据的集合。当然oc中也有这种数据类型,比如NSArray NSSet等等。那这些有什么区别呢,遇到数据处理又该选择使用哪一个呢?带着这些问题,去看下RACSequence的实现。

完整测试用例在这里

RACSequence继承于RACStream,也是一种 流 的概念,所以对于RACStream的操作方法,RACSequence也是适用的,这样就可以很方便的通过一些block实现对数据的处理。接下来,看下RACSequence中的属性和方法的作用。

  • head 序列的第一个元素,如果序列为空,返回一个nil
  • tail 原序列除去第一个元素,剩下的序列。同样的,如果源序列为空,返回一个nil
  • array 将序列元素组合成一个数组array
  • objectEnumerator 返回一个NSEnumerator对象,用于对序列进行快速遍历。与NSArray遍历相似。
  • eagerSequence 之前信号的分析中说过信号分为 冷信号 和 热信号。而序列也是一样,通过这个属性就可以获得一个原序列对应的热序列。冷序列与热序列的区别在后面的代码分析中具体区分。
  • lazySequence 获取一个原序列对应的冷序列。
  • - (RACSignal *)signal; 获取一个把序列值作为信号值的信号。
  • - (RACSignal *)signalWithScheduler:(RACScheduler *)scheduler; 获取一个把序列值作为信号值的信号,并且信号值的发送发生在scheduler调度器上。
  • - (id)foldLeftWithStart:(id)start reduce:(id (^)(id accumulator, id value))reduce; 将序列值从头到尾通过reduce计算出一个结果。
  • - (id)foldRightWithStart:(id)start reduce:(id (^)(id first, RACSequence *rest))reduce; 将序列值从尾到头通过reduce计算出一个结果。
  • - (BOOL)any:(BOOL (^)(id value))block; 类似RACSignal中的any:方法,检测序列中是否存在一个值符合block的规则。
  • - (BOOL)all:(BOOL (^)(id value))block; 类似RACSignal中的all:方法,检测序列中是否所有值符合block的规则。
  • - (id)objectPassingTest:(BOOL (^)(id value))block; 获取序列中第一个满足block条件的序列值。
  • + (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence *(^)(void))tailBlock; 序列的初始化方法,此方法要求headBlock tailBlock应当线程安全,同时headBlock不能为nil
下面分析RACSequence中的方法。
+ (RACSequence *)sequenceWithHeadBlock:(id (^)(void))headBlock tailBlock:(RACSequence *(^)(void))tailBlock {
    return [[RACDynamicSequence sequenceWithHeadBlock:headBlock tailBlock:tailBlock] setNameWithFormat:@"+sequenceWithHeadBlock:tailBlock:"];
}

该方法是序列的初始化方法, 方法中通过其子类RACDynamicSequence完成初始化工作。其实RACSequence的实现与NSArray类似,也是通过类簇分工实现不同的功能。

测试用例:

- (void)test_sequenceWithHeadBlock
{
    RACSequence *sequence1 = [RACSequence sequenceWithHeadBlock:^id{
        return @(1);
    } tailBlock:nil];
    RACSequence *sequence2 = [RACSequence sequenceWithHeadBlock:^id{
        return @"x";
    } tailBlock:^RACSequence *{
        return sequence1;
    }];

    NSLog(@"sequenceWithHeadBlock -- %@ -- %@", sequence1, sequence2);

    // 打印日志:
    /*
     2018-08-13 17:29:11.779905+0800 TestRACSequence[91431:11665825] sequenceWithHeadBlock -- <RACDynamicSequence: 0x6000000937e0>{ name = , head = (unresolved), tail = (null) } -- <RACDynamicSequence: 0x600000092570>{ name = , head = (unresolved), tail = (unresolved) }
     */
}

- (id)head {
    NSCAssert(NO, @"%s must be overridden by subclasses", __func__);
    return nil;
}

- (RACSequence *)tail {
    NSCAssert(NO, @"%s must be overridden by subclasses", __func__);
    return nil;
}

RACSequence作为抽象类,提供一个默认实现。

测试用例:

- (void)test_head_tail
{
    RACSequence *sequence1 = [RACSequence sequenceWithHeadBlock:^id{
        return @(1);
    } tailBlock:nil];
    RACSequence *sequence2 = [RACSequence sequenceWithHeadBlock:^id{
        return @"x";
    } tailBlock:^RACSequence *{
        return sequence1;
    }];
    NSLog(@"head_tail -- %@ -- %@ -- %@", sequence2, sequence2.head, sequence2.tail);

    // 打印日志:
    /*
     2018-08-13 17:35:23.971686+0800 TestRACSequence[91710:11683638] head_tail -- <RACDynamicSequence: 0x6000002827b0>{ name = , head = x, tail = <RACDynamicSequence: 0x600000285730>{ name = , head = (unresolved), tail = (null) } } -- x -- <RACDynamicSequence: 0x600000285730>{ name = , head = (unresolved), tail = (null) }
     */
}

+ (instancetype)empty {
    return RACEmptySequence.empty;
}

RACStream中方法的实现,返回一个RACEmptySequence对象。

测试用例:

- (void)test_empty
{
    RACSequence *sequence = [RACSequence empty];
    NSLog(@"empty -- %@", sequence);

    // 打印日志:
    /*
     2018-08-13 17:36:49.308519+0800 TestRACSequence[91788:11688256] empty -- <RACEmptySequence: 0x60400001cf90>{ name =  }
     */
}

+ (instancetype)return:(id)value {
    return [RACUnarySequence return:value];
}

RACStream中方法的实现,由RACUnarySequence处理value

测试用例:

- (void)test_return
{
    RACSequence *sequence = [RACSequence return:@(1)];
    NSLog(@"return -- %@", sequence);

    // 打印日志:
    /*
     2018-08-13 17:38:49.967036+0800 TestRACSequence[91890:11694680] return -- <RACUnarySequence: 0x60400023f580>{ name = , head = 1 }
     */
}

- (instancetype)bind:(RACStreamBindBlock (^)(void))block {
    RACStreamBindBlock bindBlock = block();
    return [[self bind:bindBlock passingThroughValuesFromSequence:nil] setNameWithFormat:@"[%@] -bind:", self.name];
}

- (instancetype)bind:(RACStreamBindBlock)bindBlock passingThroughValuesFromSequence:(RACSequence *)passthroughSequence {
    // Store values calculated in the dependency here instead, avoiding any kind
    // of temporary collection and boxing.
    //
    // This relies on the implementation of RACDynamicSequence synchronizing
    // access to its head, tail, and dependency, and we're only doing it because
    // we really need the performance.
    __block RACSequence *valuesSeq = self;
    __block RACSequence *current = passthroughSequence;
    __block BOOL stop = NO;

    RACSequence *sequence = [RACDynamicSequence sequenceWithLazyDependency:^ id {
        while (current.head == nil) {
            if (stop) return nil;

            // We've exhausted the current sequence, create a sequence from the
            // next value.
            id value = valuesSeq.head;

            if (value == nil) {
                // We've exhausted all the sequences.
                stop = YES;
                return nil;
            }

            current = (id)bindBlock(value, &stop);
            if (current == nil) {
                stop = YES;
                return nil;
            }

            valuesSeq = valuesSeq.tail;
        }

        NSCAssert([current isKindOfClass:RACSequence.class], @"-bind: block returned an object that is not a sequence: %@", current);
        return nil;
    } headBlock:^(id _) {
        return current.head;
    } tailBlock:^ id (id _) {
        if (stop) return nil;

        return [valuesSeq bind:bindBlock passingThroughValuesFromSequence:current.tail];
    }];

    sequence.name = self.name;
    return sequence;
}

RACStream中方法的实现。主要功能是通过RACDynamicSequencesequenceWithLazyDependency:headBlock:tailBlock:方法实现的。现在先看下每个block的含义。
* dependencyBlock 先根据currenthead是否存在分条件处理。

假设`current.head == nil`,就会开始循环,循环中先拿到序列自身的`head`然后做判空处理,为空直接返回`nil`;不为空调用`bindBlock`将序列自身的`value`做转换,如果转换的值不存在,返回`nil`;如果存在,那么序列自身去掉头部,并开始对转换的序列`current`继续循环操作。
  • headBlock 返回参数序列的头部。
  • tailBlock 序列自身调用方法本身并以参数序列的尾部为参数。

这里只是单纯对方法表面的分析,具体实现逻辑还是要参考RACDynamicSequence代码,所以,后面对RACDynamicSequence的分析会重新来看这个方法的作用。

测试用例:

- (void)test_bind
{
    RACSequence *sequence = [RACSequence return:@(1)];
    RACSequence *sequence1 = [sequence bind:^RACStreamBindBlock{
        return ^(id value, BOOL *stop){
            return [RACSequence return:@"x"];
        };
    }];
    NSLog(@"bind -- %@", sequence1);

    // 打印日志:
    /*
     2018-08-13 17:44:28.092128+0800 TestRACSequence[92150:11712416] bind -- <RACUnarySequence: 0x604000430de0>{ name = , head = x }
     */
}

- (instancetype)concat:(RACStream *)stream {
    NSCParameterAssert(stream != nil);

    return [[[RACArraySequence sequenceWithArray:@[ self, stream ] offset:0]
        flatten]
        setNameWithFormat:@"[%@] -concat: %@", self.name, stream];
}

RACStream中方法的实现。通过RACArraySequencesequenceWithArray:offsetself stream组合成一个序列,再通过方法flatten最终由RACSequencebind:方法返回一个RACDynamicSequence序列。

测试用例:

- (void)test_concat
{
    RACSequence *sequence1 = [RACSequence return:@(1)];
    RACSequence *sequence2 = [RACSequence return:@"x"];
    RACSequence *quence = [sequence1 concat:sequence2];
    NSLog(@"concat -- %@", quence);
    NSLog(@"concat -- %@ -- %@ -- %@", quence.head, quence.tail, quence.tail.head);

    // 打印日志
    /*
     2018-08-13 17:54:42.848858+0800 TestRACSequence[92582:11743087] concat -- <RACDynamicSequence: 0x60400009e000>{ name = , head = (unresolved), tail = (unresolved) }
     2018-08-13 17:54:42.849428+0800 TestRACSequence[92582:11743087] concat -- 1 -- <RACDynamicSequence: 0x60400009e730>{ name = , head = x, tail = (unresolved) } -- x
     */
}

- (instancetype)zipWith:(RACSequence *)sequence {
    NSCParameterAssert(sequence != nil);

    return [[RACSequence
        sequenceWithHeadBlock:^ id {
            if (self.head == nil || sequence.head == nil) return nil;
            return RACTuplePack(self.head, sequence.head);
        } tailBlock:^ id {
            if (self.tail == nil || [[RACSequence empty] isEqual:self.tail]) return nil;
            if (sequence.tail == nil || [[RACSequence empty] isEqual:sequence.tail]) return nil;

            return [self.tail zipWith:sequence.tail];
        }]
        setNameWithFormat:@"[%@] -zipWith: %@", self.name, sequence];
}

RACStream中方法的实现。作用是将两个序列的序列值两两结合成元祖。

测试用例:

- (void)test_zip
{
    RACSequence *sequence1 = [RACSequence return:@(1)];
    RACSequence *sequence2 = [RACSequence return:@"x"];
    RACSequence *quence = [sequence1 zipWith:sequence2];
    NSLog(@"concat -- %@", quence);
    NSLog(@"concat -- %@ -- %@", quence.head, quence.tail);

    // 打印日志
    /*
     2018-08-13 17:57:01.474478+0800 TestRACSequence[92683:11750366] concat -- <RACDynamicSequence: 0x60000008d660>{ name = , head = (unresolved), tail = (unresolved) }
     2018-08-13 17:57:01.478114+0800 TestRACSequence[92683:11750366] concat -- <RACTuple: 0x60000001d640> (
     1,
     x
     ) -- (null)
     */
}

- (NSArray *)array {
    NSMutableArray *array = [NSMutableArray array];
    for (id obj in self) {
        [array addObject:obj];
    }

    return [array copy];
}

通过使用for in 循环返回一个NSMutableArray对象。

测试用例:

- (void)test_array
{
    RACSequence *sequence1 = [RACSequence return:@(1)];
    RACSequence *sequence2 = [RACSequence return:@"x"];
    RACSequence *sequence = [sequence1 concat:sequence2];
    NSLog(@"array -- %@", sequence);
    NSLog(@"array -- %@", sequence.array);

    // 打印日志:
    /*
     2018-08-13 18:00:09.420123+0800 TestRACSequence[92822:11759844] array -- <RACDynamicSequence: 0x60000028a8c0>{ name = , head = (unresolved), tail = (unresolved) }
     2018-08-13 18:00:09.421563+0800 TestRACSequence[92822:11759844] array -- (
     1,
     x
     )
     */
}

- (NSEnumerator *)objectEnumerator {
    RACSequenceEnumerator *enumerator = [[RACSequenceEnumerator alloc] init];
    enumerator.sequence = self;
    return enumerator;
}

@implementation RACSequenceEnumerator

- (id)nextObject {
    id object = nil;

    @synchronized (self) {
        object = self.sequence.head;
        self.sequence = self.sequence.tail;
    }

    return object;
}

@end

objectEnumerator方法获取一个RACSequenceEnumerator对象用于循环。而RACSequenceEnumerator中实现了nextObject方法,提供了循环下一步的操作。

测试用例:

- (void)test_objectEnumerator
{
    RACSequence *sequence1 = [RACSequence return:@(1)];
    RACSequence *sequence2 = [RACSequence return:@"x"];
    RACSequence *sequence = [sequence1 concat:sequence2];
    NSEnumerator *enumerator = [sequence objectEnumerator];
    id x;
    while (x = [enumerator nextObject]) {
        NSLog(@"objectEnumerator -- %@", x);
    }

    // 打印日志:
    /*
     2018-08-13 18:04:54.179471+0800 TestRACSequence[93045:11774396] objectEnumerator -- 1
     2018-08-13 18:04:54.180524+0800 TestRACSequence[93045:11774396] objectEnumerator -- x
     */
}

- (RACSignal *)signal {
    return [[self signalWithScheduler:[RACScheduler scheduler]] setNameWithFormat:@"[%@] -signal", self.name];
}

- (RACSignal *)signalWithScheduler:(RACScheduler *)scheduler {
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        __block RACSequence *sequence = self;

        return [scheduler scheduleRecursiveBlock:^(void (^reschedule)(void)) {
            if (sequence.head == nil) {
                [subscriber sendCompleted];
                return;
            }

            [subscriber sendNext:sequence.head];

            sequence = sequence.tail;
            reschedule();
        }];
    }] setNameWithFormat:@"[%@] -signalWithScheduler: %@", self.name, scheduler];
}

该方法返回一个signal。当该信号被订阅时,通过RACSchedulerscheduleRecursiveBlock方法将序列的值逐个发送出去。

测试用例:

- (void)test_signal
{
    RACSequence *sequence = [RACSequence return:@(1)];
    RACSignal *signal1 = [sequence signal];
    RACScheduler *scheduler = [RACScheduler scheduler];
    RACSignal *signal2 = [sequence signalWithScheduler:scheduler];
    NSLog(@"signal -- %@ -- %@ -- %@", signal1, scheduler, signal2);

    [signal1 subscribeNext:^(id x) {
        NSLog(@"signal -- %@ -- %@", x, [RACScheduler currentScheduler]);
    }];

    [signal2 subscribeNext:^(id x) {
        NSLog(@"signal -- %@ -- %@", x, [RACScheduler currentScheduler]);
    }];

    // 打印日志:
    /*
     2018-08-13 18:12:01.468921+0800 TestRACSequence[93338:11795985] signal -- <RACDynamicSignal: 0x6040004231a0> name:  -- <RACTargetQueueScheduler: 0x6040004231c0> com.ReactiveCocoa.RACScheduler.backgroundScheduler -- <RACDynamicSignal: 0x6040004231e0> name:
     2018-08-13 18:12:01.469827+0800 TestRACSequence[93338:11796059] signal -- 1 -- <RACTargetQueueScheduler: 0x604000423040> com.ReactiveCocoa.RACScheduler.backgroundScheduler
     Test Case '-[TestRACSequenceTests test_signal]' passed (0.003 seconds).
     2018-08-13 18:12:01.469858+0800 TestRACSequence[93338:11796058] signal -- 1 -- <RACTargetQueueScheduler: 0x6040004231c0> com.ReactiveCocoa.RACScheduler.backgroundScheduler
     */
}

- (id)foldLeftWithStart:(id)start reduce:(id (^)(id, id))reduce {
    NSCParameterAssert(reduce != NULL);

    if (self.head == nil) return start;

    for (id value in self) {
        start = reduce(start, value);
    }

    return start;
}

通过for循环将序列的值与startreduce运算,并保存结果用于与序列的下个值进行运算,重复此过程直到序列结束。

测试用例:

- (void)test_foldLeftWithStart
{
    RACSequence *sequence = [RACSequence return:@(1)];
    id x = [sequence foldLeftWithStart:@(100) reduce:^id(id accumulator, id value) {
        return @([accumulator intValue] + [value intValue]);
    }];
    NSLog(@"foldLeftWithStart -- %@", x);

    // 打印日志:
    /*
     2018-08-13 18:15:10.572439+0800 TestRACSequence[93473:11805347] foldLeftWithStart -- 101
     */
}

- (id)foldRightWithStart:(id)start reduce:(id (^)(id, RACSequence *))reduce {
    NSCParameterAssert(reduce != NULL);

    if (self.head == nil) return start;

    RACSequence *rest = [RACSequence sequenceWithHeadBlock:^{
        return [self.tail foldRightWithStart:start reduce:reduce];
    } tailBlock:nil];

    return reduce(self.head, rest);
}

通过sequenceWithHeadBlock方法实现序列值从尾部开始进行reduce运行,最后获取一个结果。这个与foldLeftWithStart:reduce:类似,只是上面的方法是从头部开始运算直到尾部。

测试用例:

- (void)test_foldRightWithStart
{
    RACSequence *sequence = [RACSequence return:@(1)];
    id x = [sequence foldRightWithStart:@(100) reduce:^id(id first, RACSequence *rest) {
        return @([first intValue] + [rest.head intValue]);
    }];

    NSLog(@"foldRightWithStart -- %@", x);

    // 打印日志:
    /*
     2018-08-13 18:18:07.610381+0800 TestRACSequence[93615:11815125] foldRightWithStart -- 1
     */
}

- (BOOL)any:(BOOL (^)(id))block {
    NSCParameterAssert(block != NULL);

    return [self objectPassingTest:block] != nil;
}

- (BOOL)all:(BOOL (^)(id))block {
    NSCParameterAssert(block != NULL);

    NSNumber *result = [self foldLeftWithStart:@YES reduce:^(NSNumber *accumulator, id value) {
        return @(accumulator.boolValue && block(value));
    }];

    return result.boolValue;
}

- (id)objectPassingTest:(BOOL (^)(id))block {
    NSCParameterAssert(block != NULL);

    return [self filter:block].head;
}

* objectPassingTest通过调用父类RACStreamfilter方法筛选,然后调用head拿到筛选的值。
* any:判断筛选的值是否存在。
* all:通过foldLeftWithStart进行block操作,获取到最后的结果,判断是否所有值都符合block条件。

测试用例:

- (void)test_any_all_objectPassingTest
{
    RACSequence *sequence = [RACSequence sequenceWithHeadBlock:^id{
        return @(3);
    } tailBlock:^RACSequence *{
        return [RACSequence return:@(2)];
    }];

    BOOL any = [sequence any:^BOOL(id value) {
        return [value integerValue] > 0;
    }];

    BOOL all = [sequence all:^BOOL(id value) {
        return [value integerValue] > 0;
    }];

    id pass = [sequence objectPassingTest:^BOOL(id value) {
        return [value integerValue] > 0;
    }];

    NSLog(@"any_all_objectPassingTest -- %d -- %d -- %@", any, all, pass);

     // 打印日志:
    /*
     2018-08-13 18:23:14.915419+0800 TestRACSequence[93823:11830326] any_all_objectPassingTest -- 1 -- 1 -- 3
     */
}

- (RACSequence *)eagerSequence {
    return [RACEagerSequence sequenceWithArray:self.array offset:0];
}

通过子类RACEagerSequence获取到一个热序列。

测试用例:

- (void)test_eagerSequence
{
    RACSequence *sequence = [RACSequence sequenceWithHeadBlock:^id{
        return @(1);
    } tailBlock:^RACSequence *{
        return nil;
    }];
    NSLog(@"eagerSequence -- %@", sequence);
    RACSequence *eager = [sequence eagerSequence];
    NSLog(@"eagerSequence -- %@ -- %@", sequence, eager);

    // 打印日志:
    /*
     2018-08-13 18:28:13.685364+0800 TestRACSequence[94050:11846212] eagerSequence -- <RACDynamicSequence: 0x6040000972a0>{ name = , head = (unresolved), tail = (unresolved) }
     2018-08-13 18:28:13.686662+0800 TestRACSequence[94050:11846212] eagerSequence -- <RACDynamicSequence: 0x6040000972a0>{ name = , head = 1, tail = (null) } -- <RACEagerSequence: 0x604000428240>{ name = , array = (
     1
     ) }
     */
}

- (RACSequence *)lazySequence {
    return self;
}

返回自身,因为自身就是个冷序列。

测试用例:

- (void)test_lazySequence
{
    RACSequence *sequence = [RACSequence sequenceWithHeadBlock:^id{
        return @(1);
    } tailBlock:^RACSequence *{
        return nil;
    }];
    RACSequence *lazy = [sequence lazySequence];
    NSLog(@"lazySequence -- %@ -- %@", sequence, lazy);

    // 打印日志:
    /*
     2018-08-13 18:51:55.549171+0800 TestRACSequence[94412:11865893] lazySequence -- <RACDynamicSequence: 0x604000481fe0>{ name = , head = (unresolved), tail = (unresolved) } -- <RACDynamicSequence: 0x604000481fe0>{ name = , head = (unresolved), tail = (unresolved) }
     */
}

下面还有一些方法,由于不涉及到核心逻辑,就不再分析了,有兴趣的看看就好。

后面会对RACSequence的子类进行分析。

猜你喜欢

转载自blog.csdn.net/jianghui12138/article/details/81808843