美文网首页
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