Observing Collections With Bindings
June 21st, 2007I just noticed a new section on mmalc’s very helpful “Cocoa Bindings Examples and Hints”:
I have personally found this very confusing when I’ve used bindings in my projects. The problem arises when you’ve got application model data stored in some “free” data structure like a dictionary or array. The model data can be manipulated quite handily with standard UI and array controllers, but what about cluing the rest of your application into the change? I find the problem of “bottom-up” observing with deeply nested data models to be one of the hardest problems with bindings, both conceptually and practically.
To me, mmalc’s explanation just confirms what I thought was true: bindings kind of sucks for nested “pure” models. There often must be some custom code associated with your model, or else you’ll have to jump through hoops to observe the changes in the data from some higher altitude.
I’m not sure what Apple should do to make it better, but I hope they do it. Or is my desire to store everything in dictionaries and arrays just a flaw in my thinking? Maybe I’m asking for too much.
June 21st, 2007 at 3:48 pm
Yeah, I find myself wanting to do this sort of thing all the time. For example, if I’m managing a table that needs to refresh anytime property X of one of the items changes, it means observing that property for each object displayed. This also means you need to add/remove yourself as an observer when items are added/removed from the list.
I did this often enough that I ended up writing a generic set of routines (a start, an update, and an end) that will observe key paths of every object in a to-many KVC relationship. It works pretty much the same way as in the GraphicsBinding example on mmalc’s page, but it takes arbitrary keys as arguments.
The start routine sets up the initial observations, then you can call the update routine from observeValueForKeyPath:… and just pass it the change NSDictionary, and it adds/removes observers as necessary for newly added/removed objects. Then there’s also an end routine that tears everything down after you’re done. It’s the kind of code that’s a pain to write, but once you’ve got it written in a reusable form, it’s very very handy to have around.
I also tend to only use dictionaries to store things for very very simple cases. My experience is that once too many keys get involved, it’s just to easy to get confused as to what’s what, so making an actual class with defined methods helps keep things straight. The temptation is always there though. :-)
June 22nd, 2007 at 2:52 am
I”™m not much of a bindings fan, but I”™ve got to agree with Brian about keeping the use of collection objects to simple cases. Working with Oolite has reinforced this, as it uses some pretty complex property list structures, some read from disk and merged together, some generated at runtime. When they were being implemented, it probably made sense, but coming in afterwards and unravelling them can be a nightmare.
I prefer to use hierarchies of simple model objects, which may or may not be wrappers for Foundation collections. This basically gives me the advantage of strong typing with introspection (even though I”™m not a hardcore strong typing fan) — if something weird is happening in the middle of a structure, it”™s generally possible to work out what type of data I”™m supposed to be providing, etc.
June 23rd, 2007 at 6:08 am
Another option is to have your derived NSManagedObject handle the change and notification itself in its setter. Of course this still requires a custom model object.
June 28th, 2007 at 12:59 am
Is there a reason why the key path
@"arrangedObjects.name"
wouldn’t work? AFAIK, it would.June 28th, 2007 at 6:34 am
Peter: how do you define “work?” The point of mmalc’s entry is to draw attention to the fact that it’s not so simple to both observe the properties of items in a collection and observe the membership of the collection.