Реактивное какао, расщепление сигнала без дублирования кода?
Я пытаюсь изменить метку на кнопке на вызываемом селекторе.
Похоже, что код дублируется. Есть ли способ, может быть, для меня сейчас неочевидно переключать сигнал после карты? или нет?
[[[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";
}];
1 ответ
Прежде всего, чтобы изменить название кнопки, вы должны вызвать ее setTitle:forState:
метод.
Также обратите внимание, что с помощью self
внутри subscribeNext
блок может создать цикл сохранения (и, следовательно, утечку памяти). Вы можете прочитать больше об этом в этом ответе. Ты можешь использовать @weakify
/ @strongify
макросы или, как уже упоминалось в этом ответе, использовать rac_liftSelectors:withSignals:
метод (который имхо кажется чище).
Ваш код может быть упрощен, так как вам вообще не нужно разделять сигнал. Вы можете использовать простое условие внутри map
заблокировать и вернуть значение, которое должно быть названием кнопки после ее нажатия. Это значение будет отправлено как next
значение результирующего сигнала. Вы также можете использовать startWith:
Оператор, чтобы установить начальное значение (я думаю, это должно быть "Пуск").
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:
). Метод вызывается с next
значения signals
как его параметры. Так что в нашем случае это будет первоначально вызвать:
[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
макросы.