ReactiveObjC - RACSequence

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操作,取出内部每个序列的值重新组成一个新序列返回。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容