Re: Exposing NSTableView's usesAlternatingRowBackgroundColors in the user preferences
Re: Exposing NSTableView's usesAlternatingRowBackgroundColors in the user preferences
- Subject: Re: Exposing NSTableView's usesAlternatingRowBackgroundColors in the user preferences
- From: Kyle Sluder <email@hidden>
- Date: Thu, 14 Jul 2011 09:29:27 -0700
On Tue, Jul 12, 2011 at 11:53 AM, Peter <email@hidden> wrote:
> I'd like to expose NSTableView's option usesAlternatingRowBackgroundColors as a settable preference in my app's preferences window. "Easy, just use a binding", I thought before I realized that NSTableView does not expose this setting via bindings, neither using IB nor programatically.
>
> I found two solutions to this problem, both of them more or less unsatisfactory. In my NSTableView's subclass +initialize method I register the default value
>
> #define defaults [NSUserDefaults standardUserDefaults]
> NSDictionary *appDefaults = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES], @"usesAlternatingRowBackgroundColors", nil];
> [defaults registerDefaults:appDefaults];
>
> whereas in -awakeFromNib I use the value stored in the user defaults
>
> #define defaultValues [[NSUserDefaultsController sharedUserDefaultsController] values]
> [self setUsesAlternatingRowBackgroundColors:[[defaultValues valueForKey:@"usesAlternatingRowBackgroundColors"] boolValue]];
>
> In my preferences panel I have bound the value key of a checkbox to the shared user defaults controller.
> This is all pretty standard and it works so far.
>
> 1. Solution
> In my preferences panel's controller I have defined the following action method for the check box
>
> - (IBAction)clickAlternatingRowsCheckbox:(id)sender{
> NSInteger checkboxState = [sender state];
> if (checkboxState == NSOffState) {
> [myTableView setUsesAlternatingRowBackgroundColors:NO];
> }
> else if (checkboxState == NSOnState) {
> [myTableView setUsesAlternatingRowBackgroundColors:YES];
> }
> }
>
> This solution saves the setting to the user defaults via bindings, but works only when the value is changed via the GUI and breaks MVC - the preferences controller should better not be hooked up with a view used elsewhere in the app. To avoid this, I deviced a
>
> 2. Solution
> I set the controller of my NSTableView's subclass as KVO observer of the key in the sharedUserDefaultsController:
>
> #define theDefaultsController [NSUserDefaultsController sharedUserDefaultsController]
> [theDefaultsController addObserver:self forKeyPath:@"values.usesAlternatingRowBackgroundColors" options: NSKeyValueObservingOptionNew context:NULL];
>
> The controller handles the observation like this
>
> - (void) observeValueForKeyPath: (NSString *) keyPath
> ofObject: (id) object
> change: (NSDictionary *) change
> context: (void *) context
> {
> if ( [keyPath isEqualToString:@"values.usesAlternatingRowBackgroundColors"] ) {
> //NSLog(@"%@", [change objectForKey:NSKeyValueChangeNewKey]);
> [self.myTableView setUsesAlternatingRowBackgroundColors:[[theDefaultsController valueForKeyPath:@"values.usesAlternatingRowBackgroundColors"] boolValue]];
> }
> }
>
> The problem is, that since [change objectForKey:NSKeyValueChangeNewKey] returns <NULL> in the log, I can't get the changed value from the change dictionary, so I have to read it from the sharedUserDefaultsController - which works, but seems pretty ridiculous. (Instead of checking the check boxes state, I could have used the same approach in the 1. solution, too, BTW.) Somehow, KVO seems to be unable to handle the boolean encoded as NSNumber. Ideas on this anybody?
No, all of this seems pretty standard.
NSController subclasses do not support NSKeyValueChangeOldKey or
NSKeyValueChangeNewKey. This is a longstanding bug in NSController.
rdar://problem/3404770
The solution is to query the object directly for its new value.
Really, this is all that NSKeyValueChangeNewKey is doing for you. See
the comments on the various -will/didChangeValueForKey: variants in
NSKeyValueObserving.h for precisely what NSKeyValueChange{Old,New}Key
contains. NSKeyValueChangeOldKey is slightly more powerful, since it
gets sent at -didChangeValueForKey: time but contains information that
only existed at -willChangeValueForKey: time. But in many cases you
can mimic its functionality using NSKeyValueObservingOptionPrior. But
I bet that doesn't work with NSController either.
In any event, keep doing what you're doing, and file a bug at
http://bugreport.apple.com saying you encountered this problem and
asking that it be fixed.
--Kyle Sluder
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden