iOS RAC系列
①、iOS-RAC的开发用法-底层分析以及总结
②、iOS-RAC-核心类分析-RACPassthroughSubscriber订阅者-RACScheduler调度者-RACDisposable销毁者-RACObseve监听者-RACSubject
③、iOS-RAC-底层分析-RAC的宏-RACCommand
(完)④、iOS-RAC-在实际开发的使用-以登录注册为例子
Demo
Demo-iOS-RAC-高阶函数-带注释
iOS-RAC-实际开发案例-登录注册
资料
iOS-RAC底层源码分析-思维导图-MindNote
RAC流程源码
- ①、RAC流程源码
- ②、RACPassthroughSubscriber(核心订阅者)
- ③、RACScheduler(调度者)
- ④、RACDisposable(销毁)
- ⑤、RACObserve
- 1.RACObserve 使用
- 2.`RACObserve`的宏定义、`_RACObserve`的宏定义 `\代表换行符号`、`rac_valuesForKeyPath`的宏定义
- 2.1RACObserve
- 2.2_RACObserve
- 2.3 rac_valuesForKeyPath
- 2.4 我们来分析`- (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver`
- 2.5 我们来分析`- (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver block:(void (^)(id, NSDictionary *, BOOL, BOOL))block`
- 2.6 `RACKVOTrampoline`反弹消息
- 2.7 `RACKVOProxy`移交代理 、`trampolines`漫游表
- ⑥.RACSubject`子类 既可以订阅也可以发送`
- ⑦、`RACMulticastConnection`的使用
①、RAC流程源码
RAC源码分析-MindNote思维导图
1.RAC流程分析 已经在 上一篇的《①、iOS-RAC的开发用法-底层分析以及总结》讲过具体可以自行查看
2.RAC核心类
3.RAC的订阅者、RAC销毁者、RAC调度者
②、RACPassthroughSubscriber(核心订阅者)
RAC的流程是: 创建信号、订阅信号 、发送信息、销毁信号
-(void)func1
{
// 1.创建信号
@weakify(self);
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
@strongify(self);
self.yhSubscriber = subscriber;
NSLog(@"来了,网络请求");
// 发送信息
[subscriber sendNext:@"yuye"];
// 3.销毁信号
return [RACDisposable disposableWithBlock:^{
NSLog(@"我们销毁了");
}];
}];
// self.signal = signal;
// 2.订阅信号 --- 保存block
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"订阅到了 : %@",x);
}];
[signal subscribeError:^(NSError * _Nullable error) {
NSLog(@"Error is %@",error);
}];
}
- (IBAction)clickBtn1:(UIButton *)sender {
// 发送消息
[self.yhSubscriber sendNext:@"RAC"];
}
- (IBAction)clickBtn2:(UIButton *)sender {
// 发送错误
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:10086 userInfo:@{@"YHError":@"haha"}];
[self.yhSubscriber sendError:error];
}
- (IBAction)clickBtn3:(UIButton *)sender {
// 发送完成信息
[self.yhSubscriber sendCompleted];
}
- (void)dealloc
{
NSLog(@"走了 销毁了----");
}
我们还是先看一下 RAC的整个流程核心代码有哪些内容
1.RACPassthroughSubscriber subscriber
订阅者
2.RACDynamicSignal 的 signal
信号
3. RACCompoundDisposable disposable
销毁
// 重点 : RAC 精髓
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
// 多态 --- 厉害
/*
RACPassthroughSubscriber
subscriber --- RACSubscriber
signal
disposable
*/
// 传递了三个参数 : subscriber 订阅者 、(self)signal 信号 、disposable 销毁者
// 信号 订阅者发送信号 销毁 --- RAC
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;
}
4.我们查看RACPassthroughSubscriber
订阅者的核心代码
- (instancetype)initWithSubscriber:(id<RACSubscriber>)subscriber signal:(RACSignal *)signal disposable:(RACCompoundDisposable *)disposable
- (instancetype)initWithSubscriber:(id<RACSubscriber>)subscriber signal:(RACSignal *)signal disposable:(RACCompoundDisposable *)disposable {
NSCParameterAssert(subscriber != nil);
self = [super init];
// 订阅者、信号、销毁者
_innerSubscriber = subscriber;
_signal = signal;
_disposable = disposable;
[self.innerSubscriber didSubscribeWithDisposable:self.disposable];
return self;
}
RACPassthroughSubscriber
发送错误sendError
发送错误的时候 直接发送了销毁信号操作
- (void)sendError:(NSError *)e {
@synchronized (self) {
// 深浅拷贝
// SDK 没有资格去修改用户传递进来的数据
// 如果 SDK 有资格修改用户传递进来的数据 说明时 有侵入。这样的SDK是不安全的
void (^errorBlock)(NSError *) = [self.error copy];
// 发送错误时 直接发送销毁操作
[self.disposable dispose];
if (errorBlock == nil) return;
errorBlock(e);
}
}
RACPassthroughSubscriber
发送完成操作sendCompleted
发送完成的时候 也是直接发送了销毁信号操作
- (void)sendCompleted {
@synchronized (self) {
void (^completedBlock)(void) = [self.completed copy];
// 发送完成时 直接发送销毁操作
[self.disposable dispose];
if (completedBlock == nil) return;
completedBlock();
}
}
总结:整体流程式
1.创建信号,保存了订阅者block+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe
2.订阅信号- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock
内部调用了RACDynamicSignal
的ubscribe
3.在subscribe
存储信息订阅者
、信号
、销毁者
4.拿到订阅者去发送信息
5.销毁
总结:
/**
订阅者
1.RAC signal subscribe dispose
2.探索订阅者 三种形式的销毁
1.直接销毁
2.调用 error 进行销毁
3.调用sendCompleted
*/
5.RACPassthroughSubscriber整体流程图
③、RACScheduler(调度者)
1.我们先从subscribeNext
找到 RACDynamicSignal
的subscribe
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
// 多态 --- 厉害
/*
RACPassthroughSubscriber
subscriber --- RACSubscriber
signal
disposable
*/
// 传递了三个参数 : subscriber 订阅者 、(self)signal 信号 、disposable 销毁者
// 信号 订阅者发送信号 销毁 --- RAC
subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
if (self.didSubscribe != NULL) {
// 多线程 --- cpu --- 自己跑了
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
RACDisposable *innerDisposable = self.didSubscribe(subscriber);
[disposable addDisposable:innerDisposable];
}];
[disposable addDisposable:schedulingDisposable];
}
return disposable;
}
2.我们在subscribe
进行分析RACScheduler
if (self.didSubscribe != NULL) {
// 多线程 --- cpu --- 自己跑了
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
RACDisposable *innerDisposable = self.didSubscribe(subscriber);
[disposable addDisposable:innerDisposable];
}];
[disposable addDisposable:schedulingDisposable];
}
2.1. 这里RACScheduler
生成了一个单例对象subscriptionScheduler
+ (RACScheduler *)subscriptionScheduler {
static dispatch_once_t onceToken;
static RACScheduler *subscriptionScheduler;
dispatch_once(&onceToken, ^{
// RACSubscriptionScheduler 就是一个调度者
subscriptionScheduler = [[RACSubscriptionScheduler alloc] init];
});
return subscriptionScheduler;
}
2.2. 订阅调度者RACSubscriptionScheduler
进行了一个方法schedule
RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
RACDisposable *innerDisposable = self.didSubscribe(subscriber);
[disposable addDisposable:innerDisposable];
}];
2.3. schedule
- (RACDisposable *)schedule:(void (^)(void))block {
NSCParameterAssert(block != NULL);
// 先检测当前的调度者是否存在。
// 如果不存在
if (RACScheduler.currentScheduler == nil) return [self.backgroundScheduler schedule:block];
block();
return nil;
}
2.4 检测currentScheduler
是否存在
如果不存在 那么拿到当前的线程的获取RACSchedulerCurrentSchedulerKey
如果 RACSchedulerCurrentSchedulerKey
存在 创建设置一个主线程
如果不存在 就会执行 2.5的逻辑 通过获取后台的调度者
并且后台的调度者
通过RACQueueScheduler
创建的时候 调用performAsCurrentScheduler
会设置RACSchedulerCurrentSchedulerKey
+ (RACScheduler *)currentScheduler {
RACScheduler *scheduler = NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey];
if (scheduler != nil) return scheduler;
if ([self.class isOnMainThread]) return RACScheduler.mainThreadScheduler;
return nil;
}
// backgroundScheduler RACQueueScheduler schedule
- (RACDisposable *)schedule:(void (^)(void))block {
NSCParameterAssert(block != NULL);
RACDisposable *disposable = [[RACDisposable alloc] init];
dispatch_async(self.queue, ^{
if (disposable.disposed) return;
[self performAsCurrentScheduler:block];
});
return disposable;
}
// RACScheduler - performAsCurrentScheduler
- (void)performAsCurrentScheduler:(void (^)(void))block {
NSCParameterAssert(block != NULL);
// If we're using a concurrent queue, we could end up in here concurrently,
// in which case we *don't* want to clear the current scheduler immediately
// after our block is done executing, but only *after* all our concurrent
// invocations are done.
RACScheduler *previousScheduler = RACScheduler.currentScheduler;
NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = self;
// 当前执行的任务扔到自动释放池里面
// auto ---
// 大量的临时变量的产生
// 自定义线程
// 执行非UI操作
@autoreleasepool {
block();
}
if (previousScheduler != nil) {
NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = previousScheduler;
} else {
[NSThread.currentThread.threadDictionary removeObjectForKey:RACSchedulerCurrentSchedulerKey];
}
}
//
2.5 如果在主线程
拿不到currentScheduler
就会去生成一个后台的调度者 backgroundScheduler
然后设置`scheduler`的优先级,优先级其实就是那GCD的重新封装一遍。
然后设置一个name`org.reactivecocoa.ReactiveObjC.RACScheduler.backgroundScheduler`
再去执行`+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority name:(NSString *)name`。全局并发队列。
`RACTargetQueueScheduler` 其实就是对GCD的进行封装
- (instancetype)init {
self = [super initWithName:@"org.reactivecocoa.ReactiveObjC.RACScheduler.subscriptionScheduler"];
_backgroundScheduler = [RACScheduler scheduler];
return self;
}
// scheduler`的优先级
+ (RACScheduler *)scheduler {
return [self schedulerWithPriority:RACSchedulerPriorityDefault];
}
// 设置name
+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority {
return [self schedulerWithPriority:priority name:@"org.reactivecocoa.ReactiveObjC.RACScheduler.backgroundScheduler"];
}
// 设置并发队列
+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority name:(NSString *)name {
return [[RACTargetQueueScheduler alloc] initWithName:name targetQueue:dispatch_get_global_queue(priority, 0)];
}
// RACTargetQueueScheduler
- (instancetype)initWithName:(NSString *)name targetQueue:(dispatch_queue_t)targetQueue {
NSCParameterAssert(targetQueue != NULL);
if (name == nil) {
name = [NSString stringWithFormat:@"org.reactivecocoa.ReactiveObjC.RACTargetQueueScheduler(%s)", dispatch_queue_get_label(targetQueue)];
}
// DISPATCH_QUEUE_SERIAL 保证调度顺序性
dispatch_queue_t queue = dispatch_queue_create(name.UTF8String, DISPATCH_QUEUE_SERIAL);
if (queue == NULL) return nil;
dispatch_set_target_queue(queue, targetQueue);
return [super initWithName:name queue:queue];
}
3.RACScheduler 整体流程图
④、RACDisposable(销毁)
1.类似信号的销毁
1.1 我们找到RACSubscriber
信号发送消息的sendNext
跟踪进去
发现上面的析构方法里面调用了 [self.disposable dispose];
我们继续往上看 看到了 compoundDisposable
是一个符合销毁者。因为每次响应有很多销毁的对象。
1.2 跟踪分析RACCompoundDisposable
这个类
我们查看RACSubscriber
创建了RACCompoundDisposable
对象 使用了addDisposable
这个方法
1.3 我们具体分析addDisposable
- (void)addDisposable:(RACDisposable *)disposable {
NSCParameterAssert(disposable != self);
if (disposable == nil || disposable.disposed) return;
BOOL shouldDispose = NO;
// 添加一个锁 为什么要添加一个锁
// 防止 线程不安全 。读写操作必须添加一个锁
pthread_mutex_lock(&_mutex);
{
// 往数组添加值
if (_disposed) {
// 添加如果达到一定的范围。为了达到一些性能 需要把之前的有的东西 进行销毁
shouldDispose = YES;
} else {
// 性能调试 得出 RACCompoundDisposableInlineCount = 2
// RACCompoundDisposableInlineCount 这个值是2
#if RACCompoundDisposableInlineCount
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
if (_inlineDisposables[i] == nil) {
_inlineDisposables[i] = disposable;
goto foundSlot;
}
}
#endif
// 如果 RACCompoundDisposableInlineCount 不是等于2 就会执行下面的代码
if (_disposables == NULL) _disposables = RACCreateDisposablesArray();
CFArrayAppendValue(_disposables, (__bridge void *)disposable);
if (RACCOMPOUNDDISPOSABLE_ADDED_ENABLED()) {
RACCOMPOUNDDISPOSABLE_ADDED(self.description.UTF8String, disposable.description.UTF8String, CFArrayGetCount(_disposables) + RACCompoundDisposableInlineCount);
}
#if RACCompoundDisposableInlineCount
foundSlot:;
#endif
}
}
pthread_mutex_unlock(&_mutex);
// Performed outside of the lock in case the compound disposable is used
// recursively.
//
if (shouldDispose) [disposable dispose];
}
1.4 我们来分析RACCompoundDisposable
的dispose
- (void)dispose {
#if RACCompoundDisposableInlineCount
RACDisposable *inlineCopy[RACCompoundDisposableInlineCount];
#endif
CFArrayRef remainingDisposables = NULL;
// 锁
pthread_mutex_lock(&_mutex);
{
_disposed = YES;
#if RACCompoundDisposableInlineCount
// 把所有的容器至空
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
inlineCopy[i] = _inlineDisposables[i];
// 完全拷贝/部分拷贝 --- 回头再分析
// 直接赋值为nil
_inlineDisposables[i] = nil;
}
#endif
remainingDisposables = _disposables;
// 直接赋值 NULL
_disposables = NULL;
}
pthread_mutex_unlock(&_mutex);
#if RACCompoundDisposableInlineCount
// Dispose outside of the lock in case the compound disposable is used
// recursively.
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
// 对象如何进行真正的销毁
// 在上面 inlineCopy 进行 copy一份
// 真正的内存回收
// 真正做到谁的事情 谁干
[inlineCopy[i] dispose];
}
#endif
if (remainingDisposables == NULL) return;
CFIndex count = CFArrayGetCount(remainingDisposables);
// 所有符合式的容器 去调用 disposeEach 这个函数
CFArrayApplyFunction(remainingDisposables, CFRangeMake(0, count), &disposeEach, NULL);
CFRelease(remainingDisposables);
}
RACCompoundDisposableaddDisposable
、dispose
只要是分析符合式的销毁 怎么去增 怎么去删 怎么去挨个处理的
2. 接下来我们分析RACDisposable
的dispose
单个销毁
// 外面 --> 用compund --- 有值数组
// 数组 --> dispose --- 销毁对象
static void disposeEach(const void *value, void *context) {
RACDisposable *disposable = (__bridge id)value;
[disposable dispose];
}
- (void)dispose {
void (^disposeBlock)(void) = NULL;
while (YES) {
// 临时变量
void *blockPtr = _disposeBlock;
// A B C
// A VS C --- NULL ---> _disposeBlock --- YES
// 防止内存偏移 因为多线程操作 很可以出现线程把性能的内存地址比较差 销毁 进行偏移
// 必须找到正确的地址
if (OSAtomicCompareAndSwapPtrBarrier(blockPtr, NULL, &_disposeBlock)) {
// 一直找 ---> disposable
if (blockPtr != (__bridge void *)self) {
disposeBlock = CFBridgingRelease(blockPtr);
}
break;
}
}
if (disposeBlock != nil) disposeBlock(); // disposeBlock 最终回调了 return [RACDisposable disposableWithBlock:^{ NSLog(@"我们销毁了");}];
}
3.RACDisposable整体流程图
⑤、RACObserve
1.RACObserve 使用
@property (nonatomic,strong) NSString *name;
[RACObserve(self, name)subscribeNext:^(id _Nullable x) {
}];
2.RACObserve
的宏定义、_RACObserve
的宏定义 \代表换行符号
、rac_valuesForKeyPath
的宏定义
2.1RACObserve
#define RACObserve(TARGET, KEYPATH) _RACObserve(TARGET, KEYPATH)
2.2_RACObserve
#define _RACObserve(TARGET, KEYPATH) \
({ \
__weak id target_ = (TARGET); \
[target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]; \
})
2.3 rac_valuesForKeyPath
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer {
return [[[self
rac_valuesAndChangesForKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:observer]
map:^(RACTuple *value) {
// -map: because it doesn't require the block trampoline that -reduceEach: uses
return value[0];
}]
setNameWithFormat:@"RACObserve(%@, %@)", RACDescription(self), keyPath];
}
2.4 我们来分析- (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver
2.4.1 其中核心的我们是看他怎么进行block回传的 我们观察return [self rac_observeKeyPath:keyPath options:options observer:observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent)
这个方法 发现有值发生改变的时候 就会block回传
- (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver {
NSObject *strongObserver = weakObserver;
keyPath = [keyPath copy];
NSRecursiveLock *objectLock = [[NSRecursiveLock alloc] init];
objectLock.name = @"org.reactivecocoa.ReactiveObjC.NSObjectRACPropertySubscribing";
__weak NSObject *weakSelf = self;
RACSignal *deallocSignal = [[RACSignal
zip:@[
self.rac_willDeallocSignal,
strongObserver.rac_willDeallocSignal ?: [RACSignal never]
]]
doCompleted:^{
// Forces deallocation to wait if the object variables are currently
// being read on another thread.
[objectLock lock];
@onExit {
[objectLock unlock];
};
}];
return [[[RACSignal
createSignal:^ RACDisposable * (id<RACSubscriber> subscriber) {
// Hold onto the lock the whole time we're setting up the KVO
// observation, because any resurrection that might be caused by our
// retaining below must be balanced out by the time -dealloc returns
// (if another thread is waiting on the lock above).
[objectLock lock];
@onExit {
[objectLock unlock];
};
__strong NSObject *observer __attribute__((objc_precise_lifetime)) = weakObserver;
__strong NSObject *self __attribute__((objc_precise_lifetime)) = weakSelf;
if (self == nil) {
[subscriber sendCompleted];
return nil;
}
// KVO --- 发现有值发生改变 - 调用block
return [self rac_observeKeyPath:keyPath options:options observer:observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
// 将值 发散出去 到 [RACObserve(self, name)subscribeNext:^(id _Nullable x) {NSLog(@"RACObserve x is %@",x);}];
[subscriber sendNext:RACTuplePack(value, change)];
}];
}]
takeUntil:deallocSignal]
setNameWithFormat:@"%@ -rac_valueAndChangesForKeyPath: %@ options: %lu observer: %@", RACDescription(self), keyPath, (unsigned long)options, RACDescription(strongObserver)];
}
2.5 我们来分析- (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver block:(void (^)(id, NSDictionary *, BOOL, BOOL))block
- (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver block:(void (^)(id, NSDictionary *, BOOL, BOOL))block {
NSCParameterAssert(block != nil);
NSCParameterAssert(keyPath.rac_keyPathComponents.count > 0);
keyPath = [keyPath copy];
NSObject *strongObserver = weakObserver;
// KVO 能观察键值 还能观察路由 比如可以观察 Dog.name
NSArray *keyPathComponents = keyPath.rac_keyPathComponents;
BOOL keyPathHasOneComponent = (keyPathComponents.count == 1);
NSString *keyPathHead = keyPathComponents[0];
NSString *keyPathTail = keyPath.rac_keyPathByDeletingFirstKeyPathComponent;
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
// The disposable that groups all disposal necessary to clean up the callbacks
// added to the value of the first key path component.
RACSerialDisposable *firstComponentSerialDisposable = [RACSerialDisposable serialDisposableWithDisposable:[RACCompoundDisposable compoundDisposable]];
RACCompoundDisposable * (^firstComponentDisposable)(void) = ^{
return (RACCompoundDisposable *)firstComponentSerialDisposable.disposable;
};
[disposable addDisposable:firstComponentSerialDisposable];
BOOL shouldAddDeallocObserver = NO;
// 这里self 就是外部调用者的对象 self
objc_property_t property = class_getProperty(object_getClass(self), keyPathHead.UTF8String);
if (property != NULL) {
rac_propertyAttributes *attributes = rac_copyPropertyAttributes(property);
if (attributes != NULL) {
@onExit {
free(attributes);
};
BOOL isObject = attributes->objectClass != nil || strstr(attributes->type, @encode(id)) == attributes->type;
BOOL isProtocol = attributes->objectClass == NSClassFromString(@"Protocol");
BOOL isBlock = strcmp(attributes->type, @encode(void(^)())) == 0;
BOOL isWeak = attributes->weak;
// If this property isn't actually an object (or is a Class object),
// no point in observing the deallocation of the wrapper returned by
// KVC.
//
// If this property is an object, but not declared `weak`, we
// don't need to watch for it spontaneously being set to nil.
//
// Attempting to observe non-weak properties will result in
// broken behavior for dynamic getters, so don't even try.
shouldAddDeallocObserver = isObject && isWeak && !isBlock && !isProtocol;
}
}
// Adds the callback block to the value's deallocation. Also adds the logic to
// clean up the callback to the firstComponentDisposable.
void (^addDeallocObserverToPropertyValue)(NSObject *) = ^(NSObject *value) {
if (!shouldAddDeallocObserver) return;
// If a key path value is the observer, commonly when a key path begins
// with "self", we prevent deallocation triggered callbacks for any such key
// path components. Thus, the observer's deallocation is not considered a
// change to the key path.
if (value == weakObserver) return;
NSDictionary *change = @{
NSKeyValueChangeKindKey: @(NSKeyValueChangeSetting),
NSKeyValueChangeNewKey: NSNull.null,
};
RACCompoundDisposable *valueDisposable = value.rac_deallocDisposable;
RACDisposable *deallocDisposable = [RACDisposable disposableWithBlock:^{
block(nil, change, YES, keyPathHasOneComponent);
}];
[valueDisposable addDisposable:deallocDisposable];
[firstComponentDisposable() addDisposable:[RACDisposable disposableWithBlock:^{
[valueDisposable removeDisposable:deallocDisposable];
}]];
};
// Adds the callback block to the remaining path components on the value. Also
// adds the logic to clean up the callbacks to the firstComponentDisposable.
void (^addObserverToValue)(NSObject *) = ^(NSObject *value) {
RACDisposable *observerDisposable = [value rac_observeKeyPath:keyPathTail options:(options & ~NSKeyValueObservingOptionInitial) observer:weakObserver block:block];
[firstComponentDisposable() addDisposable:observerDisposable];
};
// Observe only the first key path component, when the value changes clean up
// the callbacks on the old value, add callbacks to the new value and call the
// callback block as needed.
//
// Note this does not use NSKeyValueObservingOptionInitial so this only
// handles changes to the value, callbacks to the initial value must be added
// separately.
NSKeyValueObservingOptions trampolineOptions = (options | NSKeyValueObservingOptionPrior) & ~NSKeyValueObservingOptionInitial;
//RACKVOTrampoline 所有信息的反弹
// KVO info 面向对象
RACKVOTrampoline *trampoline = [[RACKVOTrampoline alloc] initWithTarget:self observer:strongObserver keyPath:keyPathHead options:trampolineOptions block:^(id trampolineTarget, id trampolineObserver, NSDictionary *change) {
// If this is a prior notification, clean up all the callbacks added to the
// previous value and call the callback block. Everything else is deferred
// until after we get the notification after the change.
if ([change[NSKeyValueChangeNotificationIsPriorKey] boolValue]) {
[firstComponentDisposable() dispose];
if ((options & NSKeyValueObservingOptionPrior) != 0) {
block([trampolineTarget valueForKeyPath:keyPath], change, NO, keyPathHasOneComponent);
}
return;
}
// From here the notification is not prior.
NSObject *value = [trampolineTarget valueForKey:keyPathHead];
// If the value has changed but is nil, there is no need to add callbacks to
// it, just call the callback block.
if (value == nil) {
block(nil, change, NO, keyPathHasOneComponent);
return;
}
// From here the notification is not prior and the value is not nil.
// Create a new firstComponentDisposable while getting rid of the old one at
// the same time, in case this is being called concurrently.
RACDisposable *oldFirstComponentDisposable = [firstComponentSerialDisposable swapInDisposable:[RACCompoundDisposable compoundDisposable]];
[oldFirstComponentDisposable dispose];
addDeallocObserverToPropertyValue(value);
// If there are no further key path components, there is no need to add the
// other callbacks, just call the callback block with the value itself.
if (keyPathHasOneComponent) {
block(value, change, NO, keyPathHasOneComponent);
return;
}
// The value has changed, is not nil, and there are more key path components
// to consider. Add the callbacks to the value for the remaining key path
// components and call the callback block with the current value of the full
// key path.
addObserverToValue(value);
block([value valueForKeyPath:keyPathTail], change, NO, keyPathHasOneComponent);
}];
// Stop the KVO observation when this one is disposed of.
[disposable addDisposable:trampoline];
// Add the callbacks to the initial value if needed.
NSObject *value = [self valueForKey:keyPathHead];
if (value != nil) {
addDeallocObserverToPropertyValue(value);
if (!keyPathHasOneComponent) {
addObserverToValue(value);
}
}
// Call the block with the initial value if needed.
if ((options & NSKeyValueObservingOptionInitial) != 0) {
id initialValue = [self valueForKeyPath:keyPath];
NSDictionary *initialChange = @{
NSKeyValueChangeKindKey: @(NSKeyValueChangeSetting),
NSKeyValueChangeNewKey: initialValue ?: NSNull.null,
};
block(initialValue, initialChange, NO, keyPathHasOneComponent);
}
RACCompoundDisposable *observerDisposable = strongObserver.rac_deallocDisposable;
RACCompoundDisposable *selfDisposable = self.rac_deallocDisposable;
// Dispose of this observation if the receiver or the observer deallocate.
[observerDisposable addDisposable:disposable];
[selfDisposable addDisposable:disposable];
return [RACDisposable disposableWithBlock:^{
[disposable dispose];
[observerDisposable removeDisposable:disposable];
[selfDisposable removeDisposable:disposable];
}];
}
2.6 RACKVOTrampoline
反弹消息
- (instancetype)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {
NSCParameterAssert(keyPath != nil);
NSCParameterAssert(block != nil);
NSObject *strongTarget = target;
if (strongTarget == nil) return nil;
self = [super init];
_keyPath = [keyPath copy];
_block = [block copy];
_weakTarget = target;
_unsafeTarget = strongTarget;
_observer = observer;
// 移交代理 -- 观察对象
// vc --> 可能观察的对象 可能是 person 、dog
[RACKVOProxy.sharedProxy addObserver:self forContext:(__bridge void *)self];
[strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];
[strongTarget.rac_deallocDisposable addDisposable:self];
[self.observer.rac_deallocDisposable addDisposable:self];
return self;
}
2.7 RACKVOProxy
移交代理 、trampolines
漫游表
2.7.1 ·
RACKVOProxy
最主要是创建trampolines
漫游表 和监听到的值 扔给漫游表
2.7.2trampolines
漫游表 将 监听的值 返回回去
RACKVOProxy
RACKVOProxy的初始化 DISPATCH_QUEUE_SERIAL
使用了串行队列 确保顺序不会错乱
- (instancetype)init {
self = [super init];
_queue = dispatch_queue_create("org.reactivecocoa.ReactiveObjC.RACKVOProxy", DISPATCH_QUEUE_SERIAL);
_trampolines = [NSMapTable strongToWeakObjectsMapTable];
return self;
}
RACKVOProxy添加监听观察者
- (void)addObserver:(__weak NSObject *)observer forContext:(void *)context {
NSValue *valueContext = [NSValue valueWithPointer:context];
dispatch_sync(self.queue, ^{
[self.trampolines setObject:observer forKey:valueContext];
});
}
RACKVOProxy发现值得改变
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
NSValue *valueContext = [NSValue valueWithPointer:context];
__block NSObject *trueObserver;
dispatch_sync(self.queue, ^{
trueObserver = [self.trampolines objectForKey:valueContext];
});
if (trueObserver != nil) {
// 将所有的值 都会返回到 RACKVOTrampoline 漫游表里面去
[trueObserver observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
RACKVOProxy移除观察者
其实就是在RACKVOTrampoline
的析构dealloc
的dispose
里面进行移除了
RACKVOTrampoline
漫游表
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context != (__bridge void *)self) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
RACKVOBlock block;
id observer;
id target;
// 面向对象 的化整为零
@synchronized (self) {
block = self.block;
observer = self.observer;
target = self.weakTarget;
}
if (block == nil || target == nil) return;
block(target, observer, change);
}
⑥.RACSubject子类 既可以订阅也可以发送
1.RACSubject的使用 注意的是先要订阅再发送才有效果
// RACSubject
-(void)RACSubject{
// // 1.创建信号
// RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// NSLog(@"信号产生");
// // 3.信号发送
// [subscriber sendNext:@"yuye"];
// // 4.销毁信号
// return [RACDisposable disposableWithBlock:^{
// NSLog(@"销毁了信号");
// }];
// }];
// // 2.订阅信号 ---- 信号订阅的产生 --- signal
// [signal subscribeNext:^(id _Nullable x) {
// NSLog(@"订阅到了 : %@",x);
// }];
// 子类 --- 发送信号还能订阅
// 需要先订阅 再发送
RACSubject *subject = [RACSubject subject];
// [subject sendNext:@"yy"]; // 执行没效果
[subject subscribeNext:^(id _Nullable x) {
NSLog(@"RACSubject x is %@",x);
}];
[subject sendNext:@"yy"]; // 执行有效果
// 应用场景 ---> 发送信号 ---> 响应信号
}
2.跟踪subscribeNext
是如何执行的。和RACScheduler
调度者一样 找到subscribe
的内部实现
RACSubject
的subscribe
内部添加了一个订阅者 通过订阅者去发送信号
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
// 不一样 --- 添加订阅者 subscribers
// signal(subscribers)
// 发送信号
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;
}
RACSubject
信号发送sendNext
- (void)sendNext:(id)value {
// 重包装了以下
[self enumerateSubscribersUsingBlock:^(id<RACSubscriber> subscriber) {
[subscriber sendNext:value];
}];
}
//
- (void)enumerateSubscribersUsingBlock:(void (^)(id<RACSubscriber> subscriber))block {
NSArray *subscribers;
// 添加了一把锁
@synchronized (self.subscribers) {
subscribers = [self.subscribers copy];
}
// 遍历订阅者
for (id<RACSubscriber> subscriber in subscribers) {
block(subscriber);
}
}
3.RACSubject的整体流程图
⑦、RACMulticastConnection
的使用
1.我们如果使用原始的信号进行订阅发送请求 如果我们发送多个订阅的情况下。如何防止网络请求不会多次请求
未使用 RACMulticastConnection
// RACSubject
-(void)RACSubjectDemo{
// 1.创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 这里会不会执行 关键看 self.didSubscribe != NULL
NSLog(@"信号产生");
[NSThread sleepForTimeInterval:1]; // 如果是网络请求 这里会请求了3次 会严重影响带宽
// 3.信号发送
[subscriber sendNext:@"yuye"];
// 4.销毁信号
return [RACDisposable disposableWithBlock:^{
NSLog(@"销毁了信号");
}];
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"1:订阅到了 : %@",x);
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"2:订阅到了 : %@",x);
}];
[signal subscribeNext:^(id _Nullable x) {
NSLog(@"3:订阅到了 : %@",x);
}];
}
---
打印结果
2022-02-19 16:11:34.698129+0800 CSDN-RAC[96525:1433363] 信号产生
2022-02-19 16:11:35.699341+0800 CSDN-RAC[96525:1433363] 1:订阅到了 : yuye
2022-02-19 16:11:35.699564+0800 CSDN-RAC[96525:1433363] 销毁了信号
2022-02-19 16:11:35.699675+0800 CSDN-RAC[96525:1433363] 信号产生
2022-02-19 16:11:36.701006+0800 CSDN-RAC[96525:1433363] 2:订阅到了 : yuye
2022-02-19 16:11:36.701504+0800 CSDN-RAC[96525:1433363] 销毁了信号
2022-02-19 16:11:36.701758+0800 CSDN-RAC[96525:1433363] 信号产生
2022-02-19 16:11:37.702451+0800 CSDN-RAC[96525:1433363] 3:订阅到了 : yuye
2022-02-19 16:11:37.702706+0800 CSDN-RAC[96525:1433363] 销毁了信号
使用了RACMulticastConnection
其实底层逻辑就是使用了RACSubjec 添加订阅者
// RACSubject
-(void)RACSubjectDemo_Sub{
// 1.创建信号
RACSignal *signal = [RACSignal createSignal:^RACDisposable * _Nullable(id<RACSubscriber> _Nonnull subscriber) {
// 这里会不会执行 关键看 self.didSubscribe != NULL
NSLog(@"信号产生");
[NSThread sleepForTimeInterval:1]; // 如果是网络请求 这里会请求了3次 会严重影响带宽
// 3.信号发送
[subscriber sendNext:@"yuye"];
// 4.销毁信号
return [RACDisposable disposableWithBlock:^{
NSLog(@"销毁了信号");
}];
}];
// 使用 RACMulticastConnection 能防止 SLog(@"信号产生"); 调用多次
// connect.signal ---> subject add subscriber ---> subject.subscribers
// 循环 --- 遍历 sendNext --- 都能来
RACMulticastConnection *connect = [signal publish];
// 2.订阅信号
[connect.signal subscribeNext:^(id _Nullable x) {
NSLog(@"1:订阅到了 : %@",x);
}];
[connect.signal subscribeNext:^(id _Nullable x) {
NSLog(@"2:订阅到了 : %@",x);
}];
[connect.signal subscribeNext:^(id _Nullable x) {
NSLog(@"3:订阅到了 : %@",x);
}];
// 函数 ---> signal 产生只执行一次
[connect connect];
}
---
打印结果
2022-02-19 16:07:58.028479+0800 CSDN-RAC[96323:1429459] 信号产生
2022-02-19 16:07:59.029769+0800 CSDN-RAC[96323:1429459] 1:订阅到了 : yuye
2022-02-19 16:07:59.030195+0800 CSDN-RAC[96323:1429459] 2:订阅到了 : yuye
2022-02-19 16:07:59.030382+0800 CSDN-RAC[96323:1429459] 3:订阅到了 : yuye
2022-02-19 16:07:59.030556+0800 CSDN-RAC[96323:1429459] 销毁了信号