ReativeCocoaRACDisposableRACSubscriber

Posted 王飞飞不会飞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ReativeCocoaRACDisposableRACSubscriber相关的知识,希望对你有一定的参考价值。

在了解RAC的过程中,RACSignal的工作处理流程中,少不了RACDisposable和RACSubscriber的参与。本文通过前文的使用代码、解读源码,来探索RACDisposable和RACSubscriber的工作原理。

RACDisposable

  • 翻译

disposable
英 [dɪˈspəʊzəbl]   美 [dɪˈspoʊzəbl]  
adj.
可任意处理的;一次性的;用后即丢弃的;可动用的;可自由支配的
n.
〈美口〉使用后随即抛掉的东西(尤指容器等)

  • 使用
- (RACSignal *)signalTest 
    RACSignal *signal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) 
        NSLog(@"this is create block");
        [subscriber sendNext:@"发送Next"];
        RACDisposable *testDisposable = [RACDisposable disposableWithBlock:^
            NSLog(@"this is dispose creat block");
        ];
        return testDisposable;
    ];
    
    RACDisposable *disposable = [signal subscribeNext:^(id x) 
        NSLog(@"this is subscribe block %@",x);
    ];
    
    [disposable dispose];

    return signal;

这段代码中出现了2个disposable,RACSignal的didSubscribe 中返回的disposable,RACSignal的subscribeNext方法的返回的disposable。这两个一个是往RACSignal内部传入一个disposable,一个是内部返回一个disposable,很容易给人一种是同一个disposable的错觉,经过打印地址,可以发现并不是同一个disposable,那其中有什么联系么?或者说这内部做了什么操作呢?

  • 源码

先看看RACDisposable的初始化方法吧

- (id)initWithBlock:(void (^)(void))block 
	NSCParameterAssert(block != nil);

	self = [super init];
	if (self == nil) return nil;

	_disposeBlock = (void *)CFBridgingRetain([block copy]); 
	OSMemoryBarrier();

	return self;

初始化方法很简单,就是吧block存起来。那这个block在什么时候调用呢?

1.RACDisposable的dispose方法

2.RACSubscriber的dealloc方法

//1.在 RACDisposable中
- (void)dispose 
	void (^disposeBlock)(void) = NULL;

	while (YES) 
		void *blockPtr = _disposeBlock;
		if (OSAtomicCompareAndSwapPtrBarrier(blockPtr, NULL, &_disposeBlock)) 
			if (blockPtr != (__bridge void *)self) 
				disposeBlock = CFBridgingRelease(blockPtr);
			

			break;
		
	

	if (disposeBlock != nil) disposeBlock();


//2.在 RACSubscriber中
- (void)dealloc 
	[self.disposable dispose];

接下来再看看RACSignal的subscribeNext方法中返回的RACDisposable的来源。

// subscribeNext方法里面调用subscribe方法,所以直接来到subscribe这个方法中来
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber 
	NSCParameterAssert(subscriber != nil);
    //新建一个RACCompoundDisposable作为返回值。
	RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
	subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];

	if (self.didSubscribe != NULL) 
		RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^
            //didSubscribe Block返回来的disposable
			RACDisposable *innerDisposable = self.didSubscribe(subscriber);
            //添加到要返回的disposable中
			[disposable addDisposable:innerDisposable];
		];

		[disposable addDisposable:schedulingDisposable];
	
	//直接返回
	return disposable;

这里看到返回的disposable和didSubscribe Block返回的innerDisposable并不是一个。也验证了使用代码中两个RACDisposable不是同一个了。

RACSubscriber

  • 使用

同RACDisposable的使用,在RACSignal的didSubscribe Block中作为回掉参数,可以使用send Next方法。

  • 源码

didSubscribe中的subscriber类型为RACPassthroughSubscriber,所以来到RACPassthroughSubscriber的 sendNext方法中

- (void)sendNext:(id)value 
	if (self.disposable.disposed) return;

	if (RACSIGNAL_NEXT_ENABLED()) 
		RACSIGNAL_NEXT(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString([value description]));
	

	[self.innerSubscriber sendNext:value];

继续往里面蹭

- (void)sendNext:(id)value 
	@synchronized (self) 
		void (^nextBlock)(id) = [self.next copy];
		if (nextBlock == nil) return;

		nextBlock(value);
	

这里执行了nextBlock。

我们看看初始化方法

+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed 
	RACSubscriber *subscriber = [[self alloc] init];

	subscriber->_next = [next copy];
	subscriber->_error = [error copy];
	subscriber->_completed = [completed copy];

	return subscriber;

我们在来看看RACPassthroughSubscriber的初始化方法

- (instancetype)initWithSubscriber:(id<RACSubscriber>)subscriber signal:(RACSignal *)signal disposable:(RACCompoundDisposable *)disposable 
	NSCParameterAssert(subscriber != nil);

	self = [super init];
	if (self == nil) return nil;

	_innerSubscriber = subscriber;
	_signal = signal;
	_disposable = disposable;

	[self.innerSubscriber didSubscribeWithDisposable:self.disposable];
	return self;
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)otherDisposable 
	if (otherDisposable.disposed) return;

	RACCompoundDisposable *selfDisposable = self.disposable;
	[selfDisposable addDisposable:otherDisposable];

	@unsafeify(otherDisposable);

	// If this subscription terminates, purge its disposable to avoid unbounded
	// memory growth.
	[otherDisposable addDisposable:[RACDisposable disposableWithBlock:^
		@strongify(otherDisposable);
		[selfDisposable removeDisposable:otherDisposable];
	]];

在往里看

- (void)addDisposable:(RACDisposable *)disposable 
	NSCParameterAssert(disposable != self);
	if (disposable == nil || disposable.disposed) return;

	BOOL shouldDispose = NO;

	OSSpinLockLock(&_spinLock);
	
		if (_disposed) 
			shouldDispose = YES;
		 else 
			#if RACCompoundDisposableInlineCount
			for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) 
				if (_inlineDisposables[i] == nil) 
					_inlineDisposables[i] = disposable;
					goto foundSlot;
				
			
			#endif

			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
		
	
	OSSpinLockUnlock(&_spinLock);

	// Performed outside of the lock in case the compound disposable is used
	// recursively.
	if (shouldDispose) [disposable dispose];

这里注意这里也有dispose方法,所以Disposable的block在这里应该也是有可能触发的。

  • 图解

根据以上的源码,这几个类的关系已经浮出水面了。这里逻辑比较绕,多看几遍源码才能理解。

这里有几点需要注意

1.RACPassthroughSubscriber不是RACSubscriber的子类,两者同遵循RACSubscriber协议 

2.RACSubscriber的didSubscribeWithDisposable方法,暂时理解为捕获disposable。其中直接调用selfDisposable 的addDisposable方法。selfDisposable也是RACCompoundDisposable类型的,RACCompoundDisposable中有_inlineDisposables数组,这里应该是吧传入的disposable存起来了。

以上是关于ReativeCocoaRACDisposableRACSubscriber的主要内容,如果未能解决你的问题,请参考以下文章