views:

1073

answers:

5

I have an iPhone application that has a MainWindow.xib holding a UITabBarController, which in turn has a UINavigationController and a custom UIViewController subclass in its ViewControllers array. The root view controller for the UINavigationController and the custom view controller are both loaded from other xib files.

The app uses core data, the stack is initialized in the app delegate (as per the convention).

The app delegate adds the UITabBarController to the window:

- (void)applicationDidFinishLaunching:(UIApplication *)application {        
    // Configure and show the window
    [window addSubview:[tabBarController view]];
    [window makeKeyAndVisible];
}

I realize that I need to propagate a pointer to the ManagedObjectContext created in the app delegate, but I don't know how to proceed (even reading all the good commentary on the topic here and here):

  • Do I propagate the ManagedObjectContext to the UITabBarController and from there on to the individual view controllers and if so, how?
  • Or do I propagate the ManagedObjectContext directly to the root view controller of the UINavigationController and to the custom view controller and how would I do that?

I guess I don't understand well enough how to work with the UITabBarController.

A: 

A more straight-forward solution is to make the ManagedObjectContext your app delegate's public property so wherever you need access to it you would do the following:

[[[UIApplication sharedApplication] delegate] sharedManagedObjectContext];

assuming that sharedManagedObjectContext is the property name.

Costique
That might work, and I'll try it, but I'm still curious how to do it following the design pattern Apple lays out in its documentation (see the link in my question). Thanks for the answer in any case.
mvexel
That really depends on your app's architecture. You don't have to setup the NSManagedObjectContext in your app delegate, especially if your use of it is restricted to one view controller, in which case you set it up in that view controller. If I can read it right, Apple suggests you initialize your view controllers passing the shared NSManagedObjectContext using a custom -initWithManagedObjectContext: method (you write something like this yourself), but this approach won't easily work for a complex view hierarchy.
Costique
No, do *not* do this. No Apple example follows this pattern; it's not recommended (see http://developer.apple.com/mac/library/documentation/DataManagement/Conceptual/CoreDataSnippets/Articles/stack.html#//apple_ref/doc/uid/TP40008283-SW1). You should pass a context or a managed object from one view controller to the next.
mmalc
+1  A: 

Good, I looked long and hard at the CoreDataBooks sample application and did it like this:

  • Created IBOutlets to the RootViewController (the top view controller of the UINavigationController) and the MapViewController (the custom view controller) in the app delegate.
  • Connected the outlets to the view controllers in the MainWindow.xib
  • Added the following code to applicationDidFinishLaunching:

    // pass the managed object context to the view controllers
    RootViewController *rootViewController = (RootViewController *)[navigationController topViewController];
    rootViewController.managedObjectContext = self.managedObjectContext;
    
    
    mapViewController.managedObjectContext = self.managedObjectContext;
    

And now it works like a charm.

mvexel
+2  A: 

If you want to use the dependency injection method to pass the managed object context with a tab bar controller, a more robust solution would be to loop on all the view controllers in applicationDidFinishLaunching:

for (id vc in tabBarController.viewControllers) {
    [vc setManagedObjectContext:self.managedObjectContext];
}
gerry3
+4  A: 

Ideally you want to pass either the NSManagedObjectContext, NSFetchedResultsController or the relevant NSManagedObject "down" into the UIViewController. This allows the "parent" to control the "child" and determine what the child should have. This creates a more loosely coupled design and allows you to easily re-arrange UIViewController instances as needed. It also makes it easier to reuse a UIViewController.

In a tab view design it is no different. Your AppDelegate passes the NSManagedObjectContext to whoever is responsible for creating the initial UIViewController instances that go into the UITabBarController. In turn that creator passes the relevant information (NSManagedObject, NSFetchedResultsController, and/or NSManagedObject instances) into the UIViewController instances as it is constructing them.

I walk though an example of this over on the MDN site (http://http://www.mac-developer-network.com/columns/coredata/coredata0907/).

Marcus S. Zarra
The link above is not working...
Sergio Oliveira Jr.
Yes, they took down the articles, I will repost it on CIMGF soon.
Marcus S. Zarra
A: 

Using Xcode 3.2.1 and targeting 3.1.3 I've had endless problems with the

rootViewController.managedObjectContext = self.managedObjectContext;

approach that mvexcel describes (and that it is used all throughout the sample apps), however using exactly the same approach but phrasing it as:

[rootViewController setManagedObjectContext:self.managedObjectContext];

works perfectly.

I've also had a lot of problems with interface builder not synching correctly with Xcode and so not being able to connect up the outlets to pass the context through. Hopefully the next release fixes all this.

benz001