I have an NSView
subclass which is bound to the arrangedObjects
of an NSArrayController
. When the array has an item inserted or removed the view is notified. How do I get it to be notified if a model stored in the array has an attribute changed?
Do I need to add my view as an observer to every (relevant) attribute of every item added to the array?
When an item is added to or removed from the array I am notified via observeValueForKeyPath:ofObject:change:context:
in my NSView
subclass. I am not notified of changes to the models stored in the array but I could, every time I am notified of an insertion, add the view as an observer to the new item's attributes. Is this the best way to do this?
I overrode addObserver
for the model class so that I could see what happens and noticed that NSTableView
columns bound to the arrangedObjects
add themselves as observers to the appropriate attributes. Can this be made to happen automagically or do I set up the observations manually?
Maybe rather than observing potentially many key value paths, why not have each object in the array post a notification when something has changed, then only one object needs to observe one notification instead of one object observing many key value paths.
EDIT:
Also, your arrayed objects could also respond to a class method called
+keyPathsForValuesAffecting<key>
where<key>
is your key name. Here's an example:paymentDue
is a key, which is affected when the valuesinvoiceItems.count
orpaymentsMade
have changed. WheninvoiceItems.count
orpaymentsMade
has changed, anything bound topaymentDue
is sent a notification.If you are running on 10.4, or are targeting 10.4 or earlier, you'll need to use this method instead, but it essentially boils down to the same thing.
EDIT 2:
To clarify your other comment; you can still have each object in the array manually call
Then, with some controller code you can register for notification updates from your objects. If you choose a unique notification name then you won't need to manually listen from specific objects, you can tell the
NSNotificationCenter
that you want to receive notifications from any object. Your controller can work out which object has changed quite easily.Register with the notification center (these methods should be in a controller object):
Implement a method to handle the notification.
Get your model objects to post notifications when parts of them change:
But
If your model is properly KVC compliant and made with the appropriate KVO callbacks, manual notifications won't be necessary.
A big thank you to dreamlax but I think I didn't do a good enough job explaining my problem. My model class was observable and produced the right notifications but I couldn't work out how to observe them without observing every item in the array directly.
I think the documentation for key paths could be improved because I couldn't find anything that explained the very simple change I needed to make. There's some good info the array magic keypaths but no simple "these are the common things" documentation.
Anyway. Previously in my
NSView
subclass I had the following:To get notification of changes to the models within the
NSArrayController
'sarrangedObjects
all I needed to add was observation ofarrangedObjects.name
(for thename
property of my model). So the above code became:That's it! Now if any object in
arrangedObjects
gets itsname
changed I am notified.