On May 7, 2012, at 20:16 , Koen van der Drift wrote:

> One of my viewcontrollers uses the representedObject to bind to the 
> NSArrayController that holds all the data for the application (OS X, ARC on). 
> I declared a local property mySelection (an NSArray) and bind it to the 
> representedObject as follows:
> 
>    [self bind:@"mySelection" toObject:self.representedObject 
> withKeyPath:@"selectedObjects" options:nil];
> 
> So far so good.
> 
> Now when the user changes mySelection,  not only my local property needs to 
> be updated, but also some other parts in my code. So I cannot just rely on 
> the automatically generated setter, and thus need to monitor a change in 
> mySelection.  After some searching I came up with the following:
> 
>    [self.representedObject addObserver:self forKeyPath:@"selectedObjects"  
> options:NSKeyValueObservingOptionNew context: nil];
> 
> and then:
> 
> - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
> change:(NSDictionary *)change context:(void *)context
> {
>    if ([keyPath isEqualToString: @"selectedObjects"])
>    {
>       // do additional stuff
>    }
>    else 
>    {
>        [super observeValueForKeyPath:keyPath ofObject:object change:change 
> context:context];
>    }
> }
> 
> Again, this all works. Whenever the user changes the selection, 
> observeValueForKeyPath: gets called and the "do additional stuff" gets 
> executed.
> 
> But I have the feeling I am over-complicating things.  From reading on this 
> subject I get the impression the approach above seems to be more for 
> monitoring properties in other classes, not in the owner class.
> 
> So, is this the correct way to do this (responding to a change in a local 
> property, or am I overlooking something very obvious?


It's not obvious why you need a "mySelection" property at all. You just want to 
"do additional stuff" when the selection changes, so:

        [self.representedObject addObserver:self forKeyPath:@"selectedObjects" 
options:NSKeyValueObservingOptionInitial context: myContext];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
change:(NSDictionary *)change context:(void *)context
{
        if (content != myContext)
                [super observeValueForKeyPath:keyPath ofObject:object 
change:change context:context];
        else if ([keyPath isEqualToString: @"selectedObjects"])
        {
                // do additional stuff
        }
}

Note that NSKeyValueObservingOptionNew is not a useful option here, and you 
probably need NSKeyValueObservingOptionInitial to get "additional stuff" for 
the initial selection (which may be nil, of course, but don't assume it). Also, 
I added the missing context.

Inside the view controller, if you need the actual selection, it's 
'[[self.representedObject] selectedObjects]'. It may be convenient to package 
this into a *readonly* property:

- (NSArray*) mySelection 
{
        return [[self.representedObject] selectedObjects];
}

If you actually need KVO compliance for "mySelection" (that is, something else 
observes *it*), then add this:

+ (NSSet*) keyPathsForValuesAffectingMySelection 
{
        return [NSSet setWithObject: @"representedObject.selectedObjects"];
}

Don't make "mySelection" readwrite -- it's really a derived property and so 
should be readonly. Also, get rid of the "bind" invocation. It was never the 
right approach.

P.S. Personally, I wouldn't bind to a NSArrayController like this, because it 
just obscures the MVC lines of your app. The array controller is getting its 
content from somewhere: from this view controller itself, from a window 
controller, or from the app delegate. Assuming the last of these (based on your 
description of the data as app-wide), then I'd give the app delegate a 
"selectionIndexes" property (of type NSIndexSet*), bind the array controller's 
"selectionIndexes" binding to this property in IB, and have the view controller 
observe the app delegate "selectionIndexes" property instead of the array 
controller "selectedObjects" property.

The rationale for this is that the array controller is merely a glue object 
foisted on you by the bindings UI conventions, and the less your code needs to 
know about it the better.

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com

Reply via email to