views:

234

answers:

1

I have a non document-based Core Data application. There's an NSTreeController that manages a collection of objects displayed in a single NSOutlineView as a source list. They are the usual kinds of things: headings, folders, smart folders, etc.

Each of these container objects has a collection of contents objects. I have three separate view controllers that display these objects in various ways (an NSTableView and two custom graphical views, if you really want to know) But these are really just three different presentations of the same data. They should always show the same objects, share the same selection, etc.

I'm also using a hierarchy of NSViewControllers to manage my views. (If I'd known about Cathy Shive's excellent KTUIKit at the time, I would have used that, but my view controllers are very similar to -- and very much inspired by -- hers)

As it stands now, I have an NSTreeController living in the view controller for the source list view. I also have an NSArrayController in each of the sub-view controllers which is bound to the NSTreeController via some overly-complicated keypaths.

So, what needs to change, in my opinion, is the following:

  • The NSTreeController needs to move out of the outline view's controller.
  • There ought to be a single NSArrayController that each of the contents views can be bound to instead of three separate ones. Although I'm less certain of this point.

What I'm having difficulty with is figuring out where these things should live. I'm having a hard time deciding which objects, if any, truly "own" the various controllers. Do the parent view controllers own it? Does the window controller? As this is application-level data, do I go so far as to make these owned by the App Delegate? (I could imagine a circumstance where a use might want to open multiple windows, although that's not currently supported) What does the StackOverflow hive mind think?

+1  A: 

NSArrayController and NSTreeController are treated more as view objects than true controllers, so it sounds like you're on the right track. I would have started about the same way you did, giving each NSViewController its own NSArrayController or NSTreeController as needed, and configuring the bindings between them at runtime through the window controller that's responsible for putting all the pieces together.

If you think it would simplify things, it doesn't sound like there would be anything wrong with moving the NSArrayController and NSTreeController objects to the window controller. You could still set up bindings to the view controller's representedObject in IB, and then create the array/tree controllers in code in your window controller at the appropriate time. Just be carefully to not get too complicated here. I've found that when you have a lot of view controllers in the same window using representedObject for different things, it's easier to create separate, typed properties so you can understand what parts go where.

I don't really understand the benefit of making the array/tree controllers part of the app delegate, but I don't know much about what you're doing there. Maybe you would benefit from making your own "data controller" object?

Questions like this can be difficult to decide upon since sometimes there's no "right" answer, but as long as you keep simplicity and understandability in mind you'll be okay. Don't be afraid to pick a plan and move on, you can always refactor later... I know there have been times when I've spent days on architecture questions like this, when I could have been working on something more practical!

Marc Charbonneau
Thanks for your thoughtful response! I've always regarded the object controllers as being more view-oriented, too. That's part of the reason for my indecision here :-) I hadn't thought about using representedObject for the controllers; I had sort of resigned myself to doing the bindings programmatically. The motivation for this question is that I've hit a point where I have to refactor. It's getting too painful to manage all the complexity of having controllers in weird places. I've also ruled out the app delegate as the appropriate place. The window feels like the most logical place for it.
Alex