美文网首页
ReactiveObjC - RACSequence

ReactiveObjC - RACSequence

作者: PPYong | 来源:发表于2018-09-07 10:47 被阅读0次

    RACSequence代表的是RAC中一组不可变的数据的集合。如果不是特别指出,序列会根据需求懒惰的评估所包含的值,序列默认就是懒惰的。


    RACSequence主要的方法和属性

    head、tail

    序列当前的偏移量对应的值即为head,序列当前偏移量+1对应的序列即为tail。注意head是一个值,tail是一个序列。

    array

    array就是把一个序列当中的值用array的形式取出来。

    eagerSequence

    @property (nonatomic, copy, readonly) RACSequence<ValueType> *eagerSequence;
    

    把一个序列转换为一个热序列,如果序列本身是热序列则返回自身。热序列会立即评估所包含的所有值。

    lazySequence

    @property (nonatomic, copy, readonly) RACSequence<ValueType> *lazySequence;
    

    把一个序列转换为一个懒序列,如果序列本身是懒序列则返回自身。懒序列会根据需求,在被调用时评估值。

    reduce

    reduce的作用是给定某个初始值i和一个处理函数p,然后对数组进行遍历,每次都是上次p函数执行的结果加上一个新值。用数学表达式就是:result = p(p(p(i,1), 2), 3)。

    foldLeft、foldRight

    - (id)foldLeftWithStart:(nullable id)start reduce:(id _Nullable (^)(id _Nullable accumulator, ValueType _Nullable value))reduce;
    - (id)foldRightWithStart:(nullable id)start reduce:(id _Nullable (^)(id _Nullable first, RACSequence *rest))reduce;
    

    根据传入的start值进行reduce操作,两个函数开始的方向不同。foldLeft每次都会调用reduce的block;foldRight会在内部进行递归,调用一次block,返回序列的第一个值first,rest.head是除first外已经按照reduce block中操作后的结果。

    all、any

    BOOL result = [sequence any:^BOOL(id value) {  return YES;  }];
    result =[sequence all:^BOOL(id value) {  return YES;  }];
    

    all和any是用来监测序列的。
    如果有一个值满足条件,block返回YES,则any返回YES。
    如果所有值满足条件,block全都返回YES,则all返回YES。

    objectPassingTest

    - (nullable ValueType)objectPassingTest:(BOOL (^)(ValueType _Nullable value))block;
    

    在block中检测序列中的值是否满足要求,返回第一个满足要求的值,如果没有满足要求的值便返回nil。

    sequenceWithHeadBlock:tailBlock:

    + (RACSequence<ValueType> *)sequenceWithHeadBlock:(ValueType _Nullable (^)(void))headBlock tailBlock:(nullable RACSequence<ValueType> *(^)(void))tailBlock;
    

    序列的懒加载方法,在调用序列时才从headBlock和tailBlock中返回head和tail。headBlock和tailBlock一旦执行,结果就会保存下来供下次取用,不会重复调用block。


    RACSequence对RACStream中抽象属性及方法的实现

    empty

    RACSequence衍生出来的RACEmptySequence.empty主要作用就是表示一个空序列,该序列是一个单例,所有序列的empty方法都返回它。

    return

    + (instancetype)return:(id)value;
    

    将一个value封装为序列。内部实现这里专门引入了一个类RACUnarySequence来表示只包含一个值的序列。

    bind

    RACStream中定义了bind,bind函数是RAC中最核心的函数,很多行为操作都是建立在bind之上,所以为了能更好理解RAC源代码我们必须弄清bind函数在做什么。
    bind方法一般来说不需要我们直接调用。
    RACStream只定义了bind但并没有实现,子类必须自己实现bind函数。
    RACSequence和RACEagerSequence的bind不同,从中也可以看出两种序列的本质区别。

    RACSequence的bind操作
    - (RACSequence *)bind:(RACSequenceBindBlock (^)(void))block;
    - (RACSequence *)bind:(RACSequenceBindBlock)bindBlock passingThroughValuesFromSequence:(RACSequence *)passthroughSequence {
        
            __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;
    
                id value = valuesSeq.head;
    
                if (value == nil) {
                    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;
    }
    

    bind:操作内部是调用bind:passingThroughValuesFromSequence:,第二个参数传空。
    懒序列head和tail的获取都发生在调用时,在调用head时先执行dependency block,然后执行headBlock,返回head值;调用tail时先执行dependency block,然后执行tailBlock,返回tail序列。

    RACEagerSequence的bind操作
    - (RACSequence *)bind:(RACSequenceBindBlock (^)(void))block {
        NSCParameterAssert(block != nil);
        RACStreamBindBlock bindBlock = block();
        NSArray *currentArray = self.array;
        NSMutableArray *resultArray = [NSMutableArray arrayWithCapacity:currentArray.count];
        
        for (id value in currentArray) {
            BOOL stop = NO;
            RACSequence *boundValue = (id)bindBlock(value, &stop);
            if (boundValue == nil) break;
    
            for (id x in boundValue) {
                [resultArray addObject:x];
            }
    
            if (stop) break;
        }
        
        return [[self.class sequenceWithArray:resultArray offset:0] setNameWithFormat:@"[%@] -bind:", self.name];
    }
    

    热序列调用bind方法时会立即循环遍历一次自身的元素。每次遍历会调用一次block,RACSequenceBindBlock返回值是一个序列,该序列也会被遍历一次取出所有值,整个过程完成后将返回所有遍历值组成的新序列。也就是说在bind方法调用时,所有的值已经被操作,这就是热序列的特点。

    concat

    将两个序列的值直接拼接在一起,组成新的序列。

    zipWith

    将两个序列对应下标的值合并成一个元组,组成的新序列所包含的值全都是元组类型,不等长的部分将被舍去,新序列长度与原较短序列的长度相同。


    RACSequence对RACStreamOperations的实现

    map

    把信号源内容映射成一个新的内容返回。map底层调用的是flattenMap,map的返回值会作为flattenMap的block的参数。

    flattenMap

    把信号源内容通过block映射成一个新的序列返回,返回的序列再重新bind给RACSequence对象。

    flatten

    当序列中的值也是RACStream类型时,直接使用flatten将会内部进行flattenMap操作,取出内部每个序列的值重新组成一个新序列返回。

    相关文章

      网友评论

          本文标题:ReactiveObjC - RACSequence

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