I am trying to change the label on a button up on the selector being called.
It appears that the code is duplicated. Is there a way perhaps it's not obvious to me right now to have the signal switch after the map ? or no ?
[[[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";
}];
First of all, in order to change the button's title, you have to call its setTitle:forState:
method.
Also please note that using self
inside the subscribeNext
block is likely to create a retain cycle (and therefore a memory leak). You can read more about it in this answer . You can use @weakify
/ @strongify
macros or, as mentioned in that answer, use rac_liftSelectors:withSignals:
method (which IMHO seems to be cleaner).
Your code can be simplified as you actually don't need to split the signal at all. You can use a simple condition inside the map
block and return the value which should be the button's title after it was pressed. This value will be sent as a next
value of the resulting signal. You can also use startWith:
operator to set the initial value (I guess it should be "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];
What does rac_liftSelector:withSignals:
do? Each time one of the signals
sends its next
value, it invokes the method identified by the selector
(in this case setTitle:forState:
). The method is invoked with next
values of the signals
as its parameters. So in our case it will initially call:
[self.startButton setTitle:@"Start" forState:UIControlStateNormal];
If you wanted to set a single property (let's say titleLabel.text
), you could bind it with RAC
macro:
RAC(self.startButton, titleLabel.text) = buttonTextSignal;
Unfortunately, it only works for setting properties, and in your case you have to call a method with two arguments, that's why you have to use rac_liftSelector:withSignals
.
As I said, you could achieve the desired result using 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];
}];
But as you can see, you should take extra care to avoid a retain cycle, using @weakify
and @strongify
macros.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.