2

My app - a document based Core Data app - is going through a second iteration and now needs multiple windows to manage several model objects. Currently it manages Events and Locations through one window and one controller. The standard generated document class acts as controller for the main window at the moment.

I now want a separate window for managing Locations model objects. It seems good design to have a separate controller (NSWindowController) for each window, but then I realised that these controllers will not have access to the Managed Object Context, which is required to access the model objects.

What is the best approach here?

EDIT:

I followed ughoavgfhw solution as follows:

  • Created a new XIB for Locations and added an Array Controller to load Location objects
  • Created a custom controller ManageLocationsController as a subclass of NSWindowController
  • Made the custom controller the File Owner in Locations XIB
  • Mapped the Array Controller's context to File Owner and keyPath document.managedObjectContext

I open the Location window with:

ManageLocationsController *aController = [[ManageLocationsController alloc] initWithWindowNibName:@"ManageLocations"];
[aController showWindow: self];

This is done from EventDocument, which is the default class generated by XCode.

When mapping the Array Controller, this left a round black exclamation mark in the keyPath field and when I open the Location window it throws an exception saying "cannot perform operation without a managed object". Obviously not good. What am I missing?

Community
  • 1
  • 1
Roger
  • 4,737
  • 4
  • 43
  • 68

1 Answers1

3

Using custom window controllers is the best way to do this. A window controller might not have direct access to the managed object context, but it has access to the document, which does. You can access it programmatically using windowController.document.managedObjectContext or from bindings with the key path document.managedObjectContext. If you want to simulate direct access to the managed object context, you could create a readonly property which loads it from the document.

// header
@property (readonly) NSManagedObjectContext *managedObjectContext;

// implementation
- (NSManagedObjectContext *)managedObjectContext {
    return self.document.managedObjectContext;
}
+ (NSSet *)keyPathsForValuesAffectingManagedObjectContext {
    return [NSSet setWithObject:@"document.managedObjectContext"];
}

The keyPathsForValuesAffectingManagedObjectContext method is used to tell the key-value observing system that any object observing the managedObjectContext property should be notified of changes whenever the paths it returns change.

In order for the window controllers to work properly, they must be added to the document using addWindowController:. If you are creating multiple windows when the document opens, then you should override makeWindowControllers in your document method to create the window controllers, since this will be called automatically at the right time. If you are creating window controllers upon request, you can make them in whatever method you want, just be sure to add them to the document.

[theDocument addWindowController:myNewController];

As for the little black exclamation mark in IB, you will just have to ignore that. The document property of NSWindowController is defined with the type NSDocument, but the managedObjectContext property is defined by the NSPersistentDocument subclass. IB is warning you that the property might not be there, but you know it will be so you can just ignore it.

ughoavgfhw
  • 39,734
  • 6
  • 101
  • 123
  • Many thanks. I've edited the questions with the results as per your answer. – Roger Oct 07 '11 at 15:24
  • @Roger Sorry, I forgot to add details on using custom window controllers with NSDocument. I'll add that now. – ughoavgfhw Oct 07 '11 at 15:31
  • Thanks for that. That helped although now I'm getting "this class is not key value coding-compliant for the key managedObjectController" exceptions. I suspect this has to do with the keyPathsForValuesAffectingManagedObjectContext method. Do I need to implement that method in my custom controller class? – Roger Oct 07 '11 at 15:57
  • Sorry, scrap that last comment. I made a typo and wasn't thinking. It all works now. Thanks again for helping out! – Roger Oct 07 '11 at 16:04