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

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思维导图

在这里插入图片描述
在这里插入图片描述

1.RAC流程分析 已经在 上一篇的《①、iOS-RAC的开发用法-底层分析以及总结》讲过具体可以自行查看

RAC流程分析


2.RAC核心类

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订阅者的核心代码
  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];
    // 多态  --- 厉害
    /*
     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];
	}
}

// 

RACScheduler调度者流程分析

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 整体流程图

RACScheduler整个主线程和子线程分析


④、RACDisposable(销毁)

1.类似信号的销毁

1.1 我们找到RACSubscriber信号发送消息的sendNext跟踪进去

RACSubscriber的sendNext方法
发现上面的析构方法里面调用了 [self.disposable dispose];
我们继续往上看 看到了 compoundDisposable 是一个符合销毁者。因为每次响应有很多销毁的对象。

1.2 跟踪分析RACCompoundDisposable 这个类

我们查看RACSubscriber创建了RACCompoundDisposable对象 使用了addDisposable这个方法
RACSubscriber创建RACCompoundDisposable对象 、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 我们来分析RACCompoundDisposabledispose

- (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);
}
RACCompoundDisposableaddDisposabledispose只要是分析符合式的销毁 怎么去增 怎么去删 怎么去挨个处理的
2. 接下来我们分析RACDisposabledispose单个销毁

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整体流程图

RACDisposalbe底层分析


⑤、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.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里面进行移除了
RACKVOProxy移除观察者

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子类 既可以订阅也可以发送

RACObseve的整体流程图


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的整体流程图

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] 销毁了信号

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宇夜iOS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值