Reactive Cocoa 在没有代码重复的情况下拆分信号?

Reactive Cocoa Splitting a signal without code duplication?

我正在尝试更改被调用的选择器上按钮的标签。

看来代码重复了。有没有一种方法,也许现在对我来说在地图之后切换信号并不明显?或者没有 ?

[[[pressedStart map:^id(id value) {
    UIButton* button = value;
    BOOL transform = [button.titleLabel.text isEqualToString:@"Start"];
    return [NSNumber numberWithBool:transform];

}] filter:^BOOL(id value) {
    return [value boolValue];
}] subscribeNext:^(id x) {
    self.start.titleLabel.text = @"Stop";
}];

[[[pressedStart map:^id(id value) {
    UIButton* button = value;
    BOOL transform = [button.titleLabel.text isEqualToString:@"Stop"];
    return [NSNumber numberWithBool:transform];
}] filter:^BOOL(id value) {
    return [value boolValue];
}] subscribeNext:^(id x) {
   self.start.titleLabel.text = @"Start";
}];

首先,要更改按钮的标题,您必须调用它的 setTitle:forState: 方法。

另请注意,在 subscribeNext 块内使用 self 可能会产生保留循环(因此会造成内存泄漏)。您可以在 this answer 中阅读更多相关信息。您可以使用 @weakify / @strongify 宏,或者如该答案中所述,使用 rac_liftSelectors:withSignals: 方法(恕我直言似乎更干净)。

您的代码可以简化,因为您实际上根本不需要拆分信号。您可以在 map 块和 return 中使用一个简单的条件,该值应该是按下按钮后的标题。该值将作为结果信号的 next 值发送。也可以使用startWith:运算符设置初始值(我猜应该是"Start")。

RACSignal *buttonTextSignal = [[pressedStart map:^id(UIButton *buttonPressed) {
    return [buttonPressed.titleLabel.text isEqualToString:@"Start"] ? @"Stop" : @"Start";
}]
startWith:@"Start"];
[self.start rac_liftSelector:@selector(setTitle:forState:) withSignals:buttonTextSignal, [RACSignal return:@(UIControlStateNormal)], nil];

rac_liftSelector:withSignals: 是做什么的?每次 signals 之一发送其 next 值时,它都会调用 selector 标识的方法(在本例中为 setTitle:forState:)。使用 signalsnext 值作为参数调用该方法。所以在我们的例子中,它最初会调用:

[self.startButton setTitle:@"Start" forState:UIControlStateNormal];

如果你想设置单个 属性(比方说 titleLabel.text),你可以用 RAC 宏绑定它:

RAC(self.startButton, titleLabel.text) = buttonTextSignal;

不幸的是,它只适用于设置属性,在你的情况下你必须调用一个有两个参数的方法,这就是你必须使用 rac_liftSelector:withSignals.

的原因

正如我所说,您可以使用 subscribeNext:

来达到预期的效果
@weakify(self);
RACSignal *buttonTextSignal = [[[pressedStart map:^id(UIButton *buttonPressed) {
    return [buttonPressed.titleLabel.text isEqualToString:@"Start"] ? @"Stop" : @"Start";
}]
startWith:@"Start"]
subscribeNext:^(NSString *title) {
    @strongify(self);
    [self.startButton setTitle:title forState:UIControlStateNormal];
}];

但是如您所见,您应该格外小心,避免使用 @weakify@strongify 宏来避免保留循环。