ReactiveCocoa 源码阅读记录。
1:RACSingle 需要订阅信号
     RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber>  _Nonnull subscriber) {
         [subscriber sendNext:@""];
         [subscriber sendCompleted];
         return nil;
     }];
     [signal subscribeNext:^(id x) {
     } error:^(NSError * _Nullable error) {
     } completed:^{
     }];
 /*************    对应的源码    **************/
 // 生成RACDynamicSignal。即生成RACSignal的子类
 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
     return [RACDynamicSignal createSignal:didSubscribe];
 }
 // 在子类中保存 didSubscribe block, 每一次订阅都会执行
 + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
     RACDynamicSignal *signal = [[self alloc] init];
     signal->_didSubscribe = [didSubscribe copy];
     return [signal setNameWithFormat:@"+createSignal:"];
 }
 /// 在订阅时执行保存在RACDynamicSignal中的didSubscribe block
 - (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;
 }
 // 生成订阅者。并调用RACDynamicSignal中的订阅方法,执行didSubscribe block
 - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
     NSCParameterAssert(nextBlock != NULL);
     RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
     return [self subscribe:o];
 }
 // 生成的订阅者中保存 nextBlock, errorBlock, completedBlock.
 + (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;
 }
 // 当订阅者收到sendNext方法时,就会执行nextBlock
 - (void)sendNext:(id)value {
     @synchronized (self) {
         void (^nextBlock)(id) = [self.next copy];
         if (nextBlock == nil) return;
         nextBlock(value);
     }
 }
2 RACSubject 既能订阅信号又能发送信号。 必须先订阅在发送。不然由于在sendNext时还没有订阅者会无法触发。
/// 事例
RACSubject *sub = [[RACSubject alloc] init];
[sub subscribeNext:^(id _Nullable x) {
NSLog(@"%@", a);
}]; [sub sendNext:@"a"];
//调用时和RACSignal有区别的方法
// 使用 subscribers 保存 订阅者。(RACDynamicSignal 还要执行didSubscrbe Block)
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil); RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable]; NSMutableArray *subscribers = self.subscribers;
@synchronized (subscribers) {
[subscribers addObject:subscriber];
} [disposable addDisposable:[RACDisposable disposableWithBlock:^{
@synchronized (subscribers) {
// Since newer subscribers are generally shorter-lived, search
// starting from the end of the list.
NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id<RACSubscriber> obj, NSUInteger index, BOOL *stop) {
return obj == subscriber;
}]; if (index != NSNotFound) [subscribers removeObjectAtIndex:index];
}
}]]; return disposable;
} // 找到需要的订阅者
- (void)enumerateSubscribersUsingBlock:(void (^)(id<RACSubscriber> subscriber))block {
NSArray *subscribers;
@synchronized (self.subscribers) {
subscribers = [self.subscribers copy];
} for (id<RACSubscriber> subscriber in subscribers) {
block(subscriber);
}
} // 这行nextBlock。
- (void)sendNext:(id)value {
[self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
[subscriber sendNext:value];
}];
}
3 bind bind是RAC中map,merge, flatten, flattenMap的基础
flattenMap 实际上就是调用bind。 经过flattenMap映射后,subscribe的是block(value)即block里面的信号
map 调用的flattenMap 经过Map映射后 subscribe的是[self return:block(value)]的信号假定为wrapSignal.而不是block(value)的信号假定为子信号。
flatten 调用的是flattenMap,subscribe的子信号。调用flatten订阅到的值必须是一个Signal。
RACSignal *returnSig = [RACSignal return:@""];
RACSignal *bindSig = [returnSig bind:^RACSignalBindBlock {
return ^RACSignal * (id value, BOOL *bl) {
return [RACSignal return:value];
};
}]; [bindSig subscribeNext:^(id _Nullable x) {
NSLog(@"%@", x);
}];
/*
* -bind: should:
* 订阅原始信号,并将订阅到的原始信号值,赋值给binding block。如果binding block返回了新的信号。订阅它, 之后用生成的中转信号的订阅者,执行返回的信号的sendNext方法和 sendComplete方法
* 1. Subscribe to the original signal of values.
* 2. Any time the original signal sends a value, transform it using the binding block.
* 3. If the binding block returns a signal, subscribe to it, and pass all of its values through to the subscriber as they're received.
* 4. If the binding block asks the bind to terminate, complete the _original_ signal.
* 5. When _all_ signals complete, send completed to the subscriber.
*
* If any signal sends an error at any point, send that to the subscriber.
*/ /*
- (RACSignal *)bind:(RACSignalBindBlock (^)(void))block {
NSCParameterAssert(block != NULL); return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
RACSignalBindBlock bindingBlock = block(); __block volatile int32_t signalCount = 1; // indicates self RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable]; void (^completeSignal)(RACDisposable *) = ^(RACDisposable *finishedDisposable) {
if (OSAtomicDecrement32Barrier(&signalCount) == 0) {
[subscriber sendCompleted];
[compoundDisposable dispose];
} else {
[compoundDisposable removeDisposable:finishedDisposable];
}
};
// signal 是bindingBlock返回的信号。订阅这个信号。由于在Block中有这个信号的sendNext方法故会直接执行他。之后接收到的值发送出去。
void (^addSignal)(RACSignal *) = ^(RACSignal *signal) {
OSAtomicIncrement32Barrier(&signalCount); RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init];
[compoundDisposable addDisposable:selfDisposable]; RACDisposable *disposable = [signal subscribeNext:^(id x) {
[subscriber sendNext:x];
} error:^(NSError *error) {
[compoundDisposable dispose];
[subscriber sendError:error];
} completed:^{
@autoreleasepool {
completeSignal(selfDisposable);
}
}]; selfDisposable.disposable = disposable;
}; @autoreleasepool {
RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init];
[compoundDisposable addDisposable:selfDisposable];
// 订阅初始的信号(上面的returnSig), 执行bindingBLock,
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(selfDisposable);
}
}
} error:^(NSError *error) {
[compoundDisposable dispose];
[subscriber sendError:error];
} completed:^{
@autoreleasepool {
completeSignal(selfDisposable);
}
}]; selfDisposable.disposable = bindingDisposable;
} return compoundDisposable;
}] setNameWithFormat:@"[%@] -bind:", self.name];
} */
ReactiveCocoa 源码阅读记录。的更多相关文章
- EventBus源码解析 源码阅读记录
		
EventBus源码阅读记录 repo地址: greenrobot/EventBus EventBus的构造 双重加锁的单例. static volatile EventBus defaultInst ...
 - flutter_boot android和flutter源码阅读记录
		
版本号0.1.54 看源码之前,我先去看下官方文档,对于其源码的设计说明,文中所说的原生都是指android 看完官方文档的说明,我有以下几个疑问 第一个:容器是怎么设计的? 第二个:native和f ...
 - Vue2.x 响应式部分源码阅读记录
		
之前也用了一段时间Vue,对其用法也较为熟练了,但是对各种用法和各种api使用都是只知其然而不知其所以然.最近利用空闲时间尝试的去看看Vue的源码,以便更了解其具体原理实现,跟着学习学习. Proxy ...
 - underscore源码阅读记录
		
这几天有大神推荐读underscore源码,趁着项目测试的空白时间,看了一下. 整个underscore包括了常用的工具函数,下面以1.3.3源码为例分析一下. _.size = function(o ...
 - Linux内核源码阅读记录一之分析存储在不同段中的函数调用过程
		
在写驱动的过程中,对于入口函数与出口函数我们会用一句话来修饰他们:module_init与module_exit,那会什么经过修饰后,内核就能狗调用我们编写的入口函数与出口函数呢?下面就来分析内核调用 ...
 - JQuery源码阅读记录
		
新建html文件,在浏览器中打开文件,在控制台输入consoole.log(window);新建html文件,引入JQuery后在浏览器中打开,在控制台同样输入consoole.log(window) ...
 - vue 源码阅读记录
		
0.webpack默认引入的是vue.runtime.common.js,并不是vue.js,功能有略微差别,不影响使用 1.阅读由ts编译后的js: 入口>构造函数 >定义各类方法 &g ...
 - underscore源码阅读记录(二)
		
引自underscore.js context参数用法 _.each(list, iteratee, [context]); context为上下文,如果传递了context参数,则把iterator ...
 - RIPS源码阅读记录(二)
		
Author: tr1ple 这部分主要分析scanner.php的逻辑,在token流重构完成后,此时ini_get是否包含auto_prepend_file或者auto_append_file 取 ...
 
随机推荐
- Web Api 2 认证与授权 2
			
HTTP Message Handler 在 Web Api 2 认证与授权 中讲解了几种实现机制,本篇就详细讲解 Message Handler 的实现方式 关于 Message Handler 在 ...
 - 【转】Centos yum 换源
			
[1] 首先备份/etc/yum.repos.d/CentOS-Base.repo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/Cent ...
 - 2018.11.16 bzoj4827: [Hnoi2017]礼物(ntt)
			
传送门 nttnttntt 入门题. 考虑展开要求的式子∑i=0n−1(xi−yi−c)2\sum_{i=0}^{n-1}(x_i-y_i-c)^2∑i=0n−1(xi−yi−c)2 => ...
 - 2018.11.02 洛谷P3952 时间复杂度(模拟)
			
传送门 惊叹考场dubuffdubuffdubuff. 这题还没有梭哈难啊233. 直接按照题意模拟就行了. 代码: #include<bits/stdc++.h> using names ...
 - Codeforces Round #520 (Div. 2) E. Company(dfs序判断v是否在u的子树里+lca+线段树)
			
https://codeforces.com/contest/1062/problem/E 题意 给一颗树n,然后q个询问,询问编号l~r的点,假设可以删除一个点,使得他们的最近公共祖先深度最大.每次 ...
 - 内联/块级元素的宽高及margin/padding的说明  |||||| 为何img、input等内联元素可以设置宽、高
			
1,内联非替换元素设置宽高是无效的,设置margin时,左右有效,上下无效.设置padding时,左右有效,而上下padding比较奇葩,内联非替换元素的上下padding会在元素内容盒不动的情况下上 ...
 - python的6种基本数据类型--集合
			
特征 1.确定性(元素必须可hash) 2.互异性(去重) 3.无序性(集合中的元素没有顺序,先后之分) >>> s = {1,1,1,2,2,3,4,5,6,7} # 创建 > ...
 - Andorid第一次作业
			
一.作业截图 二.项目路径 https://git.coding.net/bestimbalance/Android.git 三.小组成员 邢路: https://www.cnblogs.com/x ...
 - load data会被当成一个事务处理ERROR 1197
			
问题现象: l有一份csv格式的文件,大小在14G左右.max_binlog_cache_size=4G. 登录mysql实例,选择对应的表通过load data往指定表里导数.大概20分钟左右,报以 ...
 - WebGIS实现在线要素编辑之ArcGIS Server 发布Feature Service 过程解析
			
WebGIS实现在线要素编辑之ArcGIS Server 发布Feature Service 过程解析 FeatureService也称要素服务,其最大的好处就是支持在线要素编辑,并将编辑同步更新到后 ...