Re: monitoring changes in a local property
Re: monitoring changes in a local property
- Subject: Re: monitoring changes in a local property
- From: Quincey Morris <email@hidden>
- Date: Mon, 07 May 2012 21:27:35 -0700
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 (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