RACChannelTerminal

我们先来看看双向绑定这件事情。
IMAGE
我们如何实现信号从A传到B,又可以从B传到A呢。利用信号的双向传递的话,我们可以用RACSubject,这样A发的信号B就能接到,而且B发的信号A也能够接收到。
IMAGE

这样也有个问题,因为A是Subject的订阅者又是接受者,A发送给B的东西,A也同样会被接受到,这是我们不希望看到的。

  • 解释:为了解决数据双向传递,特别设计的一个类
  • 作用:上面已经有描述不再说了
  • 案例:
    1
    2
    3
    4
    5
    6
    // 建立双向绑定方式1
    RACChannelTo(self,string1) = RACChannelTo(self,string2);
    // 建立双向绑定方式2
    self.channel1 = [[RACKVOChannel alloc] initWithTarget:self keyPath:@"string1" nilValue:nil];
    self.channel2 = [[RACKVOChannel alloc] initWithTarget:self keyPath:@"string2" nilValue:nil];
    self.channel1[@"followingTerminal"] = self.channel2[@"followingTerminal"];

方案2只是方案1的展开,我们平时用的都是RACKVOChannel。所以以此为例

  • 订阅关系
    IMAGE
    特别解释:
  1. lead中的value等于follow的other
    3=7 4=6 10=12 11=13
  2. 同一个Terminal中的信号不会进行互相传递,因为使用ignoreValues进行了忽略(只是提及大可忽略这条规则)
  3. string1和string2并不是真正的订阅者。这边只是为了显示方便给大家演示这么写了。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    @implementation RACChannel
    - (instancetype)init {
    self = [super init];
    RACReplaySubject *leadingSubject = [[RACReplaySubject replaySubjectWithCapacity:0] setNameWithFormat:@"leadingSubject"];
    RACReplaySubject *followingSubject = [[RACReplaySubject replaySubjectWithCapacity:1] setNameWithFormat:@"followingSubject"];
    [[leadingSubject ignoreValues] subscribe:followingSubject];
    [[followingSubject ignoreValues] subscribe:leadingSubject];
    // 结合下面的Terminal初始化,即可看到leaf的value和follow的other是相等的
    _leadingTerminal = [[[RACChannelTerminal alloc] initWithValues:leadingSubject otherTerminal:followingSubject] setNameWithFormat:@"leadingTerminal"];
    _followingTerminal = [[[RACChannelTerminal alloc] initWithValues:followingSubject otherTerminal:leadingSubject] setNameWithFormat:@"followingTerminal"];
    return self;
    }
    @end
    @implementation RACChannelTerminal
    - (instancetype)initWithValues:(RACSignal *)values otherTerminal:(id<RACSubscriber>)otherTerminal {
    NSCParameterAssert(values != nil);
    NSCParameterAssert(otherTerminal != nil);
    self = [super init];
    _values = values;
    _otherTerminal = otherTerminal;
    return self;
    }
    @end
  • 发送流程
  1. String1开始发出了属性改变的信号。
  2. 由1.2.3这个value订阅者进行信号的接收
  3. 由于3=7,3又是热信号,收到信号后进行信号转发发送给13这个订阅者
  4. 由于13=11,11为热信号,收到信号后,发送给订阅者。执行setValue:ForKey:将值进行传递
  • 看下代码
    步骤1中的关键代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 这段是KVC注册属性变化之后的信号回调处理
    RACDisposable *observationDisposable = [strongTarget rac_observeKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:nil block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
    if (!causedByDealloc && affectedOnlyLastComponent && self.currentThreadData.ignoreNextUpdate) {
    [self destroyCurrentThreadData];
    return;
    }
    // 交给了leadingTerminal进行信号转发
    [self.leadingTerminal sendNext:value];
    }];

在Terminal中,我们可以看到其实terminal只是作为包装而已,真正发送和订阅时由value和other来进行订阅和发送的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
@implementation RACChannelTerminal
#pragma mark Lifecycle
- (instancetype)initWithValues:(RACSignal *)values otherTerminal:(id<RACSubscriber>)otherTerminal {
NSCParameterAssert(values != nil);
NSCParameterAssert(otherTerminal != nil);
self = [super init];
_values = values;
_otherTerminal = otherTerminal;
return self;
}
#pragma mark RACSignal
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
return [self.values subscribe:subscriber];
}
#pragma mark <RACSubscriber>
- (void)sendNext:(id)value {
[self.otherTerminal sendNext:value];
}
- (void)sendError:(NSError *)error {
[self.otherTerminal sendError:error];
}
- (void)sendCompleted {
[self.otherTerminal sendCompleted];
}
- (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable {
[self.otherTerminal didSubscribeWithDisposable:disposable];
}
@end

步骤4中的关键代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[[self.leadingTerminal
finally:^{
[observationDisposable dispose];
}]
subscribeNext:^(id x) {
NSObject *object = (keyPathComponentsCount > 1 ? [self.target valueForKeyPath:keyPathByDeletingLastKeyPathComponent] : self.target);
if (object == nil) return;
[self createCurrentThreadData];
self.currentThreadData.ignoreNextUpdate = YES;
// 可以看到收到信号后,进行setValue:forKey:进行赋值
[object setValue:x ?: nilValue forKey:lastKeyPathComponent];
} error:^(NSError *error) {
NSCAssert(NO, @"Received error in %@: %@", self, error);
// Log the error if we're running with assertions disabled.
NSLog(@"Received error in %@: %@", self, error);
}];