ReactiveCocoa 代码阅读笔记 (2) Signal的实现机制
上篇讲了RAC和RACObserve两个宏的实现机制,但都是把RACSignal当作一个黑盒来理解。 本篇详细讲解Signal的内部机制。
创建Signal
Signal有很多种创建方式,例如
是用1
[UITextView rac_textSignal]
的方式。这里我们先看看
自定义创建的Signal:1
signalForSelector:
// RACSignal.m
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
return [RACDynamicSignal createSignal:didSubscribe];
}
// RACDynamicSignal.m
+ (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe {
RACDynamicSignal *signal = [[self alloc] init];
signal->_didSubscribe = [didSubscribe copy];
return [signal setNameWithFormat:@"+createSignal:"];
}
方法接收一个block, 把这个block存在1
createSignal
属性中。顾名思义,这个block会在1
_didSubscribe
的时候被调用。1
subscribe
subscribe一个signal
下面看最常用的
的定义1
subscribeNext
// RACSignal.m
- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock error:(void (^)(NSError *error))errorBlock completed:(void (^)(void))completedBlock {
RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:errorBlock completed:completedBlock];
return [self subscribe:o];
}
会创建一个1
subscribeNext
对象, 它保存了1
RACSubscriber
, 1
nextBlock
和1
errorBlock
,这些block将在1
completedBlock
, 1
sendNext
和1
sendError
时调用:1
sendCompleted
// RACSubscriber.m
- (void)sendNext:(id)value {
@synchronized (self) {
void (^nextBlock)(id) = [self.next copy];
if (nextBlock == nil) return;
nextBlock(value);
}
}
- (void)sendError:(NSError *)e {
@synchronized (self) {
void (^errorBlock)(NSError *) = [self.error copy];
[self.disposable dispose];
if (errorBlock == nil) return;
errorBlock(e);
}
}
- (void)sendCompleted {
@synchronized (self) {
void (^completedBlock)(void) = [self.completed copy];
[self.disposable dispose];
if (completedBlock == nil) return;
completedBlock();
}
}
可以看到,
是线程安全的,并且1
sendNext
是和1
nextBlock
在同一个线程上执行的。1
sendNext
我们回到
, 1
RACSignal
会调用1
subscribeNext
:1
subscribe
// RACDynamicSignal.m
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
NSCParameterAssert(subscriber != nil);
RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
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;
}
可以看作和1
RACPassthroughSubscriber
功能一样,这里不细讲,所以1
subscriber
就是调用了1
subscribe:
并传入一个block, 在这个block中调用了1
RACScheduler.subscriptionScheduler schedule:
,也就是1
didSubscribe
中的block。所以我们可以得到一个结论:对于1
createSignal
创建的信号,每1
createSignal
一次,其block就被调用一次。1
subscribe
返回一个单例的1
RACScheduler.subscriptionScheduler
对象, 其1
RACSubscriptionScheduler
方法:1
schedule
// RACSubscriptionScheduler.m
- (RACDisposable *)schedule:(void (^)(void))block {
NSCParameterAssert(block != NULL);
if (RACScheduler.currentScheduler == nil) return [self.backgroundScheduler schedule:block];
block();
return nil;
}
这个方法会找
, 这个方法在主线程上或者在1
RACScheduler.currentScheduler
内部(schedule中的schedule)会返回非1
schedule
, 此时直接调用block; 如果不在主线程上,最外层schedule会使用1
nil
,也就是在一个background queue上执行block.1
backgroundScheduler
因此, 如果createSignal在主线程上执行,(之后调用subscribe时)signal的
(也就是1
didSubscribe
传入的block)也会在主线程上执行。1
createSignal
一般自定义的signal会在
这个block中(或者其后续)调用1
didSubscribe
等方法,这样1
[subscriber sendNext]
中传入的block就会执行。应该注意到的是1
subscribeNext:
中传入的block会和1
subscirbeNext:
在同一个线程上执行。1
sendNext
rac_signalForSelector:
这个方法很重要,它为各种1
rac_signalForSelector:
的delegate方法封装提供了基础。这个方法产生一个signal, 这个signal会在receiver执行某个selector时发送函数调用的参数。以UITextView为例:1
UIView
// NSObject+RACSelectorSignal
- (RACSignal *)rac_signalForSelector:(SEL)selector;
// UITextView+RACSignalSupport.m
- (RACSignal *)rac_textSignal {
@weakify(self);
RACSignal *signal = [[[[[RACSignal
defer:^{
@strongify(self);
return [RACSignal return:RACTuplePack(self)];
}]
concat:[self.rac_delegateProxy signalForSelector:@selector(textViewDidChange:)]]
reduceEach:^(UITextView *x) {
return x.text;
}]
takeUntil:self.rac_willDeallocSignal]
setNameWithFormat:@"%@ -rac_textSignal", self.rac_description];
RACUseDelegateProxy(self);
return signal;
}
这里会用一个
作为1
self.rac_delegateProxy
的proxy,调用1
TextView
也就是产生了一个信号, 当1
[self.rac_delegateProxy signalForSelector:@selector(textViewDidChange:)]
调用时触发。1
[delegate textViewDidChange:]
中创建了一个1
rac_signalForSelector
(一个可以手动控制进行1
subject
的信号), 做了很复杂的swizzling, 其中和发送信号相关的是1
sendNext
, 这个方法改写了原本的1
RACSwizzleForwardInvocation
. 然后将自己的对应selector的方法替换成1
forwardInvocation
,这个1
forwardInvocation
里面会调用1
forwardInvocation
发送信号给subscriber.1
[subject sendNext:]
一句话概括:
会”劫持” 1
rac_textSignal
方法,然后在这个方法调用时,把这个方法传入的参数发送给subscriber。这个劫持过程的实现是由1
UITextView.delegate的textViewDidChange:
方法完成的。1
[NSObject rac_signalForSelector:]