[TOC]
Subscriber like todo : 订阅者的操作
订阅者 Subscriber 可以调用三个常见的方法,sendNext,sendError,sendComplete
sendNext可以发送很多次,但是直到遇到了Error或者Complete之后就结束了。
这里可以查看三个方法的源码,得到这个的证明:
1 |
|
RACPassthroughSubscriber 核心穿透订阅者
订阅的流程,调用的 RACSignal
类中的 subscriptNext
方法,其实是调用类本身的另外一个方法:subscribe:subscriber
方法,实现如下:
详见上图中有这个方法
1 | - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber { |
这里有一个核心类:RACPassthroughSubscriber
,我把他称之为穿透订阅者
。
穿透订阅者的这个生成方法,我们一看传入了三个参数:subscriber,signal,disposable,有了这桑个参数,是不是基本上可以重写RAC了,所以这个类很关键,可以说它是核心穿透订阅者
了。
RACPassthroughSubscriber 的 init 方法
1 | - (instancetype)initWithSubscriber:(id<RACSubscriber>)subscriber |
最后给 _innerSubscriber 其实也就是 订阅者 subscriber 关联了一个回调方法,在销毁的时候互相回调使用的:
1 | - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)d { |
调度者 RACSchedule
Schedule
里面全部都是多线程相关的操作
SRCSubscriptionScheduler
是一个单例对象,订阅调度者。
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:
这个方法调用的时候,调用了 RACSubscriptionScheduler.m
的 schedule
方法:
RACSubscriptionScheduler.m ———— schedule
1 | - (RACDisposable *)schedule:(void (^)(void))block { |
它会调用 scheduler
的 currentScheduler
判断:
1 | + (RACScheduler *)currentScheduler { |
所以这个代码有三种情况:
- 主线程第一次进入:当前线程的TLS里面,没有这个key对应的值,判断是否在主线程,在的话返回主线程的
mainThreadScheduler
- 子线程第一次进入:…不在主线程,返回
nil
- 第二次进入,这个表里面有值了,之前子线程进来的时候下面章节填充上的,返回取出来的scheduler。存值的实际后面讲。
发生了第二个情况的话,返回的是nil,RACSubscriptionScheduler.m ———— schedule里面就会继续调用一个属性叫做 backgroundScheduler
这个backgroundScheduler
的声明路程是这样的:
- init初始化的时候他被init
[RACScheduler scheduler]
- scheduler 这个方法返回了:
[self schedulerWithPriority:RACSchedulerPriorityDefault]
[self schedulerWithPriority:priority name:@"org.reactivecocoa.ReactiveObjC.RACScheduler.backgroundScheduler"];
- 板凳君自己创建了一个全局并发队列:
[[RACTargetQueueScheduler alloc] initWithName:name targetQueue:dispatch_get_global_queue(priority, 0)];
解释一下参数,优先级是上面第二点传递过来的RACSchedulerPriorityDefault
- 这个方法的实现:
1 | - (instancetype)initWithName:(NSString *)name |
这里可以看到,串行一个队列,串行子线程操作它保证异步,但是调度的时候串行来入队
牺牲了信号的并发,保证调度的有序。
所以这个backgroundScheduler
就是一个自定义的串行队列
那么这个自定义串行上调用了 schedule
方法,实现如下:
RACQueueScheduler.m ———— schedule
1 | - (RACDisposable *)schedule:(void (^)(void))block { |
performAsCurrentScheduler
1 | - (void)performAsCurrentScheduler:(void (^)(void))block { |
把 self 自己,放进刚刚的那个线程里面的TLS的字典里面去,下次很方便。执行Block。更新字典表(目前是板凳调度者,如果有previous也就是主体的那个调度者,就把主体调度者放进字典表)。
这里操作了字典表,当前线程的TLS里面也有值了,所以第三点也成立了,子线程进来之后直接取值出调度者,直接执行了block,不用再调用 backgroundScheduler
的方法了
RACObserve 原理
试用的第一个Demo,给copy过来,凑一下字数和排版
1 | // count 是 self 的 @property |
RACObserve
的原理,这个是一个宏,两句话可以说明白:
第一句话:观察体封装成了一个对象 RACKVOTrampoline
,这一通操作,返回 RACSignal
。
第二句话:接收观察的中间代理 proxy 是个全局单例,接收所有的 observer 回调,进行派发。
remove 的原理:RACKVOTrampoline
的析构,delloc 里面 remove 所有的观察。
RACSubject 全能订阅者
单独使用它既可以发送也可以订阅,但是记住先订阅再发送,demo如下:
1 | RACSubject *sub = [RACSubject subject]; |
整个流程跟上面篇章里面的订阅流程类似。
Subject 实现自主收发的原理
三点:
RACSubject
在工厂方法初始化的时候,内部创建了一个订阅者的数组。- 在
subscribeNext
的时候,进行了把刚创建的核心穿透订阅者
添加到数组的操作。 - 在
sendNext
的时候,遍历了这个数组,挨个发送了block
。
根据这三点扒一下源代码:
1. RACSubjext init 时初始化数组:
1 | - (instancetype)init { |
2. 核心穿透订阅者
创建后就被添加进数组
1 | - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber { |
3. sendNext
遍历数组,发送 Block
1 | - (void)sendNext:(id)value { |
RACMulticastConnection
工厂的方法是publish,调用connect.subscribeNext 不会重复生成。
RAC 宏定义
RAC 的宏在预编译阶段,是一个特别宏大的系统,他提个的是一个宏定义系统,可以单独研究很久很久。。。。。。
@weakify
@ 的作用是从C语言编译到OC,例如字符串。
weakify最终的效果就是
__weak __typeof__(self) self_weak_ = self;
- Post link: http://yangzai360.top/2020/11/28/RAC_02_CreateSignal/
- Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.