Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactiveCocoa Enable NSButton based on NSTableView selection state

I have just started learning Reactive Cocoa. I am writing cocoa application where i want to enable the NSButton only if at least one row is selected in NSTableView.

I am using the following code in 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];

This code executed fine and made the addButton disabled during the app launch as there was no row selected Initially.

I want to make add Button enabled when ever TableView entry is selected. I don't know how to achieve in reactive way.

I could achieve the required behavior in the following manner.Not sure if this is the correct way to achieve it.

     [[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];
        }
    }
}];

Any suggestion is appreciated to handle the requirement in reactive way.

Thank you

like image 315
jpsasi Avatar asked Dec 26 '22 15:12

jpsasi


1 Answers

You're on the right track. There are a few changes you should make to simplify.

First, use the RAC() macro to do simple bindings like this to a property.

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

This will cause a compilation error because there is no declared property for enabled (and the getter is named isEnabled, not just `enabled). This can be fixed very simply with a category:

@interface NSButton (EnabledProp)

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

@end

Then, you can construct a signal directly from the table view's numberOfSelectedRows using another macro, RACObserve().

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

But that needs to be a BOOL for it to make sense as a binding. Transforming one type of value into another? That's a map:.

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

The NSInteger from numberOfSelectedRows is wrapped up in an NSNumber when it's in the signal, so unwrap it, compare to zero, and then wrap the comparison result back up.

like image 166
jscs Avatar answered Dec 28 '22 09:12

jscs