2014-01-15 3 views
4

Я только что начал изучать реактивные какао. Я пишу приложение какао, где я хочу включить NSButton, только если в NSTableView выбрана хотя бы одна строка.ReactiveCocoa Включить NSButton на основе состояния выбора NSTableView

Я использую следующий код в awakeFromNib

RACSignal *enableSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) { 
    @strongify(self); 
    if ([self.genreListTableView numberOfSelectedRows] > 0) { 
     [subscriber sendNext:@YES]; 
    } else { 
     [subscriber sendNext:@NO]; 
    } 
    return nil; 
}]; 

[self.addButton rac_liftSelector:@selector(setEnabled:) 
         withSignals:enableSignal,nil]; 

Этот код выполняется хорошо, и сделал AddButton отключены во время запуска приложения, поскольку не было ни в одной строке выбран Изначально.

Я хочу, чтобы кнопка добавления включалась, когда была выбрана запись TableView. Я не знаю, как достичь реактивным способом.

Я мог бы достичь требуемого поведения следующим образом. Не уверен, что это правильный способ его достижения.

 [[self rac_signalForSelector:@selector(tableViewSelectionDidChange:) 
       fromProtocol:@protocol(NSTableViewDelegate)] subscribeNext:^(RACTuple *value) { 
    NSNotification *notification = value.first; 
    if (self.genreListTableView == notification.object) { 
     if ([self.genreListTableView numberOfSelectedRows] > 0) { 
      [self.addButton setEnabled:TRUE]; 
     } else { 
      [self.addButton setEnabled:FALSE]; 
     } 
    } 
}]; 

Любое предложение принято для удовлетворения требований реактивным способом.

Спасибо

ответ

8

Вы на правильном пути. Есть несколько изменений, которые вы должны сделать для упрощения.

Сначала используйте макрос RAC(), чтобы сделать простые привязки, подобные этому, к свойству.

RAC(self.addButton, enabled) = /* A signal */; 

Это вызовет ошибку компиляции, потому что нет объявленного свойства для enabled (и геттера называется isEnabled, а не только `включен). Это может быть исправлено очень просто с категорией:

@interface NSButton (EnabledProp) 

@property (assign, nonatomic, getter = isEnabled, setter = setEnabled:) BOOL enabled; 

@end 

Тогда можно построить сигнал непосредственно с точки зрения таблицы numberOfSelectedRows с использованием другого макроса RACObserve().

RAC(self.addButton, enabled) = RACObserve(self.genreListTableView, numberOfSelectedRows); 

Но это должно быть BOOL для того, чтобы иметь смысл, как связывание. Преобразование одного типа значения в другое? Это map:.

RAC(self.addButton, enabled) = [RACObserve(self.genreListTableView, numberOfSelectedRows) map:^id (NSNumber * numSelected){ 
              return @([numSelected integerValue] > 0); 
}]; 

NSInteger от numberOfSelectedRows завернута в NSNumber, когда он находится в сигнале, поэтому разворачивать его, по сравнению с нуля, а затем обернуть результат сравнения обратно вверх.

+0

Я подвожу ошибку компиляции «Ни один метод геттер для чтения из собственности» в RAC (self.addButton, включен). NSButton не имеет такого свойства, как UIButton. – jpsasi

+0

Обновлен мой ответ на адрес, @jpsasi. –

+0

компиляция проблема разрешена. но теперь у меня есть время выполнения AssertFailure со следующим сообщением об ошибке: «Signal имя: -enabled уже привязан к ключу« включено »на объекте , добавление сигнала < RACDynamicSignal: 0x61000024b940> name: [RACObserve (, numberOfSelectedRows)] -map: isdedeined behavior " – jpsasi

2

Используя подход Джоша Caswell, вы можете изменить замечание следующим образом:

[[[RACObserve(self.genreListTableView, numberOfSelectedRows) distinctUntilChanged] deliverOn:[RACScheduler mainThreadScheduler]] subscribeNext:^(NSNumber* numSelected) { 
    [self.addButton setEnabled:([numSelected integerValue] > 0)]; 
}]; 
+0

Я добавил этот блок кода в метод awakeFromNib. это выполняется только один раз, когда приложение запускается. после того, как код-код НЕ запускается, хотя я выбираю запись в tableview. Но метод делегата tableview (- (void) notificationViewSelectionDidChange: (NSNotification *)) вызывается каждый раз, когда я выбираю tableview. я удалил делегата tableview и попробовал его, сигнал не запускается. я делаю что-то неправильно здесь ?. – jpsasi

+0

'subscribeNext:' почти всегда следует избегать, если это возможно. В этом случае это не только возможно, это легко избежать. \ –

+0

@JoshCaswell Я извиняюсь за оффтоп: я не настолько продвинутый пользователь ReactiveCocoa, но позвольте мне задать вопрос: почему мы должны избегать (почти всегда) с помощью 'subscribeNext:' selector? Благодарю. Надеюсь, это даст мне информацию о «лучших практиках». –

Смежные вопросы