You can't make up items on the fly in outlineView:child:ofItem:
. All of your items must already exist, or at least continue to exist afterward until they are deleted (i.e., removed on the user's behalf from both view and model) or until whatever the outline view is showing is dismissed (e.g., document closed).
Dictionary literals (@{ … }
) represent the creation of a dictionary at that point. Whenever your program gets to that line, it will create a new dictionary, every time, even for the same child of the same item. (This is necessarily true when the dictionary includes something that isn't constant, such as the values of both index
and returnValue
.)
Even if you keep the dictionaries around, though, using plain old dictionaries and/or arrays for your model makes for very hairy code very quickly.
The solution
Make a simple subclass of NSObject with two properties:
value
(or something more specific), which is whatever kind of value you're showing in the outline viewchildren
(or something more specific), which is an array of whatever descendant items each item may contain
Then keep an array of those objects. When asked for a child of nil
, return one of the objects in that array. When asked for a child of an item, that item will be one of these objects, so return one of its children
.
When asked for the object value (for what I assume is your one and only column) of an item, return the item's value
. If you have multiple columns, have a property for each column.
Most importantly, create all of these objects before the outline view is even visible and keep them around until you are done with them (whether by deletion of an item or by dismissal of the view). Don't create items as needed and then expect the outline view to hang on to them for you—that's not its job; that's your job as the controller.
The items don't have to all be the same class; if it makes sense for your app, you can have Foos owning Bars and Bars owning Bazzes. If your needs are simple, it may make more sense for everything to be a Foo. Do whichever makes sense. Either way, custom objects add clarity to your code.
More to the point, it's also much more obvious when you're dropping a custom object on the floor versus dropping a dictionary created by a literal. It's much easier to see return [[Foo alloc] init…]
and be reminded “oh, right, I need to hang on to that”.