RACChannel
RACChannel
是一对一的双向的数据流
RACChannel
在channel中向外暴露的有两个属性terminal
@property (nonatomic, strong, readonly) RACChannelTerminal<ValueType> *leadingTerminal;
@property (nonatomic, strong, readonly) RACChannelTerminal<ValueType> *followingTerminal;
初始化terminal
方法
- (instancetype)init {
self = [super init];
RACReplaySubject *leadingSubject = [RACReplaySubject replaySubjectWithCapacity:0];
RACReplaySubject *followingSubject = [RACReplaySubject replaySubjectWithCapacity:1];
[[leadingSubject ignoreValues] subscribe:followingSubject];
[[followingSubject ignoreValues] subscribe:leadingSubject];
_leadingTerminal = [[RACChannelTerminal alloc] initWithValues:leadingSubject otherTerminal:followingSubject];
_followingTerminal = [[RACChannelTerminal alloc] initWithValues:followingSubject otherTerminal:leadingSubject]
return self;
}
- 可以看到
leadingSubject
是由Capacity:0
的RACReplaySubject
而followingSubject
是由Capacity:1
的RACReplaySubject
ignoreValues
通过订阅相互信号的错误信息,当一端出现错误信息能保证相互发送,防止当一方出错时 另外一方还在工作followingSubject
的Capacity
为1,有初始值,因此当订阅followingTerminal信息时 可以直接进行初始化状态
RACChannelTerminal: RACSignal< RACSubscriber>
初始化
ChannelTerminal
初始化,使用一个用于subcribe的RACSignal
的value 和一个用于发送值的id<RACSubscriber>
的otherTerminal
期指那个value
表示当前端点,otherTerminal
表示远程端点
@property (nonatomic, strong, readonly) RACSignal<ValueType> *values;
@property (nonatomic, strong, readonly) id<RACSubscriber> otherTerminal;
- (instancetype)initWithValues:(RACSignal *)values otherTerminal:(id<RACSubscriber>)otherTerminal {
self = [super init];
_values = values;
_otherTerminal = otherTerminal;
return self;
}
订阅信号
订阅信号 其实订阅和接收的是self.values
的信号,即订阅的时当前信号消息
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
return [self.values subscribe:subscriber];
}
发送
如果向Terminal
发送消息 会被转发到远程端点上,因此当前端点的订阅者并不能接收到当前端点发送的消息
- (void)sendNext:(id)value {
[self.otherTerminal sendNext:value];
}
使用
我们不应该直接初始化RACChannelTerminal
实例,而可以通过 初始化RACChannle的方式生成
RACChannel的使用
RACChannel+UIControl
UIControl rac_channelForControlEvents:(UIControlEvents)controlEvents key:(NSString *)key nilValue:(nullable id)nilValue {
RACChannel *channel = [[RACChannel alloc] init];
RACSignal *eventSignal = [[[self
rac_signalForControlEvents:controlEvents]
mapReplace:key]
takeUntil:[[channel.followingTerminal
ignoreValues]
catchTo:RACSignal.empty]];
[[self
rac_liftSelector:@selector(valueForKey:) withSignals:eventSignal, nil]
subscribe:channel.followingTerminal];
RACSignal *valuesSignal = [channel.followingTerminal
map:^(id value) {
return value ?: nilValue;
}];
[self rac_liftSelector:@selector(setValue:forKey:) withSignals:valuesSignal, [RACSignal return:key], nil];
return channel.leadingTerminal;
}
eventSignal
获取事件触发的signal
并将error转换为empty信号,发送的值即为keyrac_liftSelector:with:
执行一个selector
方法,rac_liftSelector:@selector(valueForKey:)
即为获取UIControl
的事件的key
的值subscribe:channel.followingTerminal
即为 channel的followingTerminal
订阅, 综合起来就是 每次事件触发时 获取key
的value值 然后发送followingTerminal
而followTerminal的sendNext
,触发leadingSubject的sendNext
,即将事件触发时获取到的value值发送给leadingSubject的订阅者 即 leadingTerminal的订阅者valueSignal
订阅followingTerminal
即 订阅 followSubject的消息,即为收到leadingTerminal发送的消息[self rac_liftSelector:@selector(setValue:forKey:) withSignals:valuesSignal, [RACSignal return:key], nil];
收到leadingTerminal
发送的消息后将收到的值传给当前的控件,保证数据同步
综合起来来说,就是在controlEvent
事件发生时,将key的value值发送给followingTerminal
,并在接收来自leadingTerminal
消息后,更新控件的key属性对应的value值
UITextField+TextChannel
- (RACChannelTerminal *)rac_newTextChannel {
return [self rac_channelForControlEvents:UIControlEventAllEditingEvents key:@keypath(self.text) nilValue:@""];
}
RACChannel+KVO
RACChannel提供了RACKVOChannel
来实现对象的某个属性值进行观测, 常可以用来进行与UIKit组件或者其他对象属性进行高效的双向绑定
RACKVOChannel :RACChannel
在KVO的channel中 我们常通过RACChannelTo
宏定义来直接使用,观测某对象属性
//参数分别为 对象、属性和默认值
#define RACChannelTo_(TARGET, KEYPATH, NILVALUE)
[[RACKVOChannel alloc] initWithTarget:(TARGET)
keyPath:@keypath(TARGET, KEYPATH) nilValue:(NILVALUE)]
[@keypath(RACKVOChannel.new, followingTerminal)]
例如:
RACChannelTerminal *integerChannel = [[RACKVOChannel alloc] initWithTarget:self keyPath:@"integerProperty" nilValue:@42][@"followingTerminal"];
先来看RACKVOChannel
的初始化方法
- (instancetype)initWithTarget:(__weak NSObject *)target keyPath:(NSString *)keyPath nilValue:(id)nilValue {
//KVO对象属性值并发送
[strongTarget rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
[self.leadingTerminal sendNext:value];
}]
// 收到订阅值 并设置对象的属性值
[[self.leadingTerminal
finally:^{
[observationDisposable dispose];
}]
subscribeNext:^(id x) {
NSObject *object = (keyPathComponentsCount > 1 ? [self.target valueForKeyPath:keyPathByDeletingLastKeyPathComponent] : self.target);
if (object == nil) return;
[object setValue:x ?: nilValue forKey:lastKeyPathComponent];
} error:^(NSError *error) {
}];
}
使用RACKVOChannel的初始化方法即获得了一个Channel对象,对此对象执行 [@keypath(RACKVOChannel.new, followingTerminal)]
来获取terminal对象是因为重写了以下两个方法:
- (RACChannelTerminal *)objectForKeyedSubscript:(NSString *)key {
RACChannelTerminal *terminal = [self valueForKey:key];
return terminal;
}
- (void)setObject:(RACChannelTerminal *)otherTerminal forKeyedSubscript:(NSString *)key {
RACChannelTerminal *selfTerminal = [self objectForKeyedSubscript:key];
[otherTerminal subscribe:selfTerminal];
[[selfTerminal skip:1] subscribe:otherTerminal];
}
重写这两个方法 就会使在调用setObject: forKeyedSubscript:
时执行-subscribe:
方法完成双向绑定