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流程源码
    • RAC源码分析-[MindNote思维导图](https://download.csdn.net/download/qq_42816425/81451003)
    • 1.RAC流程分析 已经在 上一篇的[《①、iOS-RAC的开发用法-底层分析以及总结》讲过具体可以自行查看](https://blog.csdn.net/qq_42816425/article/details/122987794?spm=1001.2014.3001.5501)
    • 2.RAC核心类
    • 3.RAC的订阅者、RAC销毁者、RAC调度者
  • ②、RACPassthroughSubscriber(核心订阅者)
    • 1.RACPassthroughSubscriber `subscriber` `订阅者`
    • 2.RACDynamicSignal 的 `signal` `信号`
    • 3. RACCompoundDisposable `disposable` ` 销毁`
    • 4.我们查看`RACPassthroughSubscriber`订阅者的核心代码
    • 5.RACPassthroughSubscriber整体流程图
  • ③、RACScheduler(调度者)
    • 1.我们先从`subscribeNext` 找到 `RACDynamicSignal`的`subscribe`
    • 2.我们在`subscribe`进行分析`RACScheduler`
      • 2.1. 这里`RACScheduler`生成了一个单例对象`subscriptionScheduler`
      • 2.2. 订阅调度者`RACSubscriptionScheduler`进行了一个方法`schedule`
      • 2.3. `schedule`
      • 2.4 检测`currentScheduler` 是否存在
      • 2.5 如果在`主线程`拿不到`currentScheduler` 就会去生成一个后台的调度者 `backgroundScheduler`
    • 3.RACScheduler 整体流程图
  • ④、RACDisposable(销毁)
    • 1.类似信号的销毁
      • 1.1 我们找到`RACSubscriber`信号发送消息的`sendNext`跟踪进去
      • 1.2 跟踪分析`RACCompoundDisposable` 这个类
      • 1.3 我们具体分析`addDisposable`
    • 1.4 我们来分析`RACCompoundDisposable`的`dispose`
      • RACCompoundDisposable`addDisposable`、`dispose`只要是分析`符合式的销毁 怎么去增 怎么去删 怎么去挨个处理的`
      • 2. 接下来我们分析`RACDisposable`的`dispose`单个销毁
    • 3.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.4.1 其中核心的我们是看他怎么进行block回传的 我们观察`return [self rac_observeKeyPath:keyPath options:options observer:observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent)`这个方法 发现有值发生改变的时候 就会block回传
      • 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`漫游表
        • RACKVOProxy
          • RACKVOProxy的初始化 `DISPATCH_QUEUE_SERIAL`使用了串行队列 确保顺序不会错乱
          • RACKVOProxy添加监听观察者
          • RACKVOProxy发现值得改变
          • RACKVOProxy移除观察者
        • `RACKVOTrampoline`漫游表
  • ⑥.RACSubject`子类 既可以订阅也可以发送`
    • 1.RACSubject的使用 `注意的是先要订阅再发送才有效果`
    • 2.跟踪`subscribeNext`是如何执行的。和`RACScheduler`调度者一样 找到`subscribe`的内部实现
      • `RACSubject`的`subscribe` 内部添加了一个订阅者 通过订阅者去发送信号
      • `RACSubject`信号发送`sendNext`
    • 3.RACSubject的整体流程图
  • ⑦、`RACMulticastConnection`的使用
    • 未使用 `RACMulticastConnection`
    • 使用了`RACMulticastConnection` `其实底层逻辑就是使用了RACSubjec 添加订阅者`

①、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];// 多态  --- 厉害/*RACPassthroughSubscribersubscriber --- RACSubscribersignaldisposable*/// 传递了三个参数 : subscriber 订阅者 、(self)signal 信号 、disposable 销毁者// 信号 订阅者发送信号 销毁 --- RACsubscriber = [[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订阅者的核心代码

  1. - (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;
}
  1. 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);}
}
  1. 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 内部调用了RACDynamicSignalubscribe
3.在subscribe 存储信息 订阅者信号销毁者
4.拿到订阅者去发送信息
5.销毁

总结:
/**
订阅者
1.RAC signal subscribe dispose
2.探索订阅者 三种形式的销毁
1.直接销毁
2.调用 error 进行销毁
3.调用sendCompleted
*/

5.RACPassthroughSubscriber整体流程图


③、RACScheduler(调度者)

1.我们先从subscribeNext 找到 RACDynamicSignalsubscribe

- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {NSCParameterAssert(subscriber != nil);RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];// 多态  --- 厉害/*RACPassthroughSubscribersubscriber --- RACSubscribersignaldisposable*/// 传递了三个参数 : subscriber 订阅者 、(self)signal 信号 、disposable 销毁者// 信号 订阅者发送信号 销毁 --- RACsubscriber = [[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 RACCompoundDisposableInlineCountfor (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 RACCompoundDisposableInlineCountfoundSlot:;#endif}}pthread_mutex_unlock(&_mutex);// Performed outside of the lock in case the compound disposable is used// recursively.//if (shouldDispose) [disposable dispose];
}

1.4 我们来分析RACCompoundDisposabledispose

- (void)dispose {#if RACCompoundDisposableInlineCountRACDisposable *inlineCopy[RACCompoundDisposableInlineCount];#endifCFArrayRef 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;}#endifremainingDisposables = _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];}#endifif (remainingDisposables == NULL) return;CFIndex count = CFArrayGetCount(remainingDisposables);// 所有符合式的容器 去调用 disposeEach 这个函数CFArrayApplyFunction(remainingDisposables, CFRangeMake(0, count), &disposeEach, NULL);CFRelease(remainingDisposables);
}

RACCompoundDisposableaddDisposabledispose只要是分析符合式的销毁 怎么去增 怎么去删 怎么去挨个处理的

2. 接下来我们分析RACDisposabledispose单个销毁

// 外面 --> 用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)) {// 一直找 ---> disposableif (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 [[[selfrac_valuesAndChangesForKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:observer]map:^(RACTuple *value) {// -map: because it doesn't require the block trampoline that -reduceEach: usesreturn 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 = [[RACSignalzip:@[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 [[[RACSignalcreateSignal:^ 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 --- 发现有值发生改变 - 调用blockreturn [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.nameNSArray *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.2 trampolines漫游表 将 监听的值 返回回去

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的析构deallocdispose里面进行移除了

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的内部实现

RACSubjectsubscribe 内部添加了一个订阅者 通过订阅者去发送信号

- (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 != NULLNSLog(@"信号产生");[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 != NULLNSLog(@"信号产生");[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] 销毁了信号

②、iOS-RAC-核心类分析-RACPassthroughSubscriber订阅者-RACScheduler调度者-RACDisposable销毁者-RACObseve监听者-RACSubject相关推荐

  1. ①、iOS-RAC的开发用法-底层分析以及总结

    iOS RAC系列 ①.iOS-RAC的开发用法-底层分析以及总结 ②.iOS-RAC-核心类分析-RACPassthroughSubscriber订阅者-RACScheduler调度者-RACDis ...

  2. 《iOS 6核心开发手册(第4版)》——2.1节UIControl类

    本节书摘来自异步社区<iOS 6核心开发手册(第4版)>一书中的第2章,第2.1节UIControl类,作者 [美]Erica Sadun,更多章节内容可以访问云栖社区"异步社区 ...

  3. 【Android 逆向】Android 逆向通用工具开发 ( 静态库项目中的网络操作核心类 CNetwork 分析 )

    文章目录 一.adabingo 静态库项目中的网络操作核心类 CNetwork 分析 一.adabingo 静态库项目中的网络操作核心类 CNetwork 分析 CNetwork 相关方法分析 : 等 ...

  4. 深入OKHttp源码分析(二)----OkHttp任务调度核心类Dispatcher解析

    OkHttp任务调度核心类Dispatcher解析 上一篇我们分析了okhttp的同步和异步请求的执行流程并进行了源码分析,深入OKHttp源码分析(一)----同步和异步请求流程和源码分析 那么今天 ...

  5. Media Player Classic - HC 源代码分析 4:核心类 (CMainFrame)(3)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  6. Media Player Classic - HC 源代码分析 3:核心类 (CMainFrame)(2)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  7. Media Player Classic - HC 源代码分析 2:核心类 (CMainFrame)(1)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  8. IOS音视频(一)AVFoundation核心类

    IOS音视频(一)AVFoundation核心类 1. AVFoundation框架架构简介 1.1 AVFoundation框架 1.2 AVFoundation 之 Assets 1.3 AVFo ...

  9. Activiti源码分析(框架、核心类。。。)

    Activiti源码分析(框架.核心类...) 目录 概 述 activiti源码分析(一)设计模式 总结: 相关工具如下: 分析: 小结: 参考资料和推荐阅读 LD is tigger foreve ...

最新文章

  1. 利用php和ajax实现的,利用PHP和AJAX实现数据库增值
  2. WebStorm配置本地测试服务器
  3. 嗯,挺全乎儿的,Spring Boot 多环境配置都在这儿了,你喜欢哪一种呢?
  4. update-rc.d: error: XXX Default-Start contains no runlevels, aborting.
  5. MobX - 基于响应式的状态管理
  6. 探探自动配对PHP_CentOS7 - 安装Apache HTTP Server和PHP
  7. 一、win7下安装yii2
  8. 乐高ev3 读取外部数据_数据就是新乐高
  9. python计算绩效工资_python实现 --工资管理系统
  10. java元数据是什么_用存储过程和 JAVA 写报表数据源有什么弊端?
  11. 一文带你了解传统手工特征的骨龄评估方法的发展历史
  12. 求1 2 3 java_求1+2+3+...+n,Java代码实现
  13. 属性绑定与双向数据绑定
  14. .net Entity Framework初识1
  15. 锐捷 linux 网卡信息失败,linux折腾日记:校园网锐捷上网设置
  16. ios下拉效果滑动滚出页面
  17. 「解析」netron 模型可视化
  18. android学习---开发Google地图应用程序
  19. java算术表达式_一文了解如何用 Java 进行算术表达式计算
  20. ffmpeg命令行,单张图片,音频合成视频

热门文章

  1. 图片保存到手机系统相册中的方法
  2. Ubuntu双系统+pytorch环境搭建日记
  3. 中国电信吴湘东:云网一体化将为运营商带来新的融合和创新
  4. C++勾股定理及拓展解题
  5. android自动修音,唱吧自动修音软件
  6. Kubernetes学习(1)-----搭建kubernetes环境
  7. Linux系统下延时任务及定时任务
  8. Altium Designer 生成 BOM(Bill of Material)
  9. Numpy与矩阵的相似对角化(Python与高等代数03)
  10. java毕业生设计高校教学资源系统计算机源码+系统+mysql+调试部署+lw