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:
)。使用 signals
的 next
值作为参数调用该方法。所以在我们的例子中,它最初会调用:
[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
宏来避免保留循环。
我正在尝试更改被调用的选择器上按钮的标签。
看来代码重复了。有没有一种方法,也许现在对我来说在地图之后切换信号并不明显?或者没有 ?
[[[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:
)。使用 signals
的 next
值作为参数调用该方法。所以在我们的例子中,它最初会调用:
[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
宏来避免保留循环。