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 取 ...
随机推荐
- 栈(NOIP2003&水题测试2017082501)
题目链接:栈 这题不难. 我们看一下,其实可以发现是卡特兰数. 不知道卡特兰数?没事,给你简单讲一下. 卡特兰数的递推式f(n)=f(0)*f(n-1)+f(1)*f(n-2)+-+f(n-2)*f( ...
- unity中的构造函数
避免使用构造函数 不要在构造函数中初始化任何变量,使用Awake或Start实现这个目的.即使是在编辑模式中Unity也自动调用构造函数,这通常发生在一个脚本被编译之后,因为需要调用构造函数来取向一个 ...
- Python10/22--面向对象编程/类与对象/init函数
类: 语法: class关键字 类名# 类名规范 大写开头 驼峰命名法class SHOldboyStudent: # 描述该类对象的特征 school = "上海Oldboy" ...
- 将excel的数据导入到数据库后都乱码了是怎么回事
将excel内容首先保存成csv格式,然后在MySQL数据库中导入,结果汉字出现了乱码. 解决过程: 1.csv文件以txt形式打开,另存为,选择utf-8编码. 2.数据库,设置,collation ...
- set集合的排序
在hibernate的OneToMany的实体关联的时候,one端的set是无序的,可是需要按照顺序来搞的话就比较麻烦了. 下面给出一个例子. Set<DiaryPicture> diar ...
- Codeforces Round #520 (Div. 2) E. Company(dfs序判断v是否在u的子树里+lca+线段树)
https://codeforces.com/contest/1062/problem/E 题意 给一颗树n,然后q个询问,询问编号l~r的点,假设可以删除一个点,使得他们的最近公共祖先深度最大.每次 ...
- IntelliJ IDEA 2017版 spring-boot2.0.4的集成JSP
一.必须依赖四个包,其中三个是springboot自带包,可以不写版本号,有一个不在springboot中,需要设置版本号 <!--引入Spring Boot内嵌的Tomcat对Jsp的解析包- ...
- GHOST完成后出现GRUB解决方法
1.试一下这个命令: grub> rootnoverify (hd0,0)(注意空格!!!) 或者 grub>makeacrive (hd0,0)grub> chainloader ...
- Json跨域请求数-Jquery Ajax请求
同步请求,async(是否异步) //同步请求,等待并接收返回的结果 var result = $.ajax({ type: "GET", url: address, async: ...
- struts1(一)流程分析