Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using FetchedResultsController and ManagedObjectContext in multiple view controllers

My RootViewController contains a simple table view. Upon selecting one of the entries in the table a DetailViewController is shown with more details on the selected entry. The data of the relevant data object is loaded and persisted via CoreData. How do I pass on the FetchedResultsController and the ManagedObjectContext to the DetailViewController in the didSelectRowAtIndexPath: method? Do I need to define properties for both in the DetailViewController.h? Can you provide me with a code sample?

like image 416
Otto64 Avatar asked Jul 19 '11 06:07

Otto64


2 Answers

Firstly, each fetched results controller (FRC) instance is configured specific to each tableview so you don't pass FRC from tableview controller to tableview controller. Instead, each tableview controller instantiates and configures a new FRC specifically for its tableview.

In a Master-Detail design where the tableview is the master view, you don't pass the FRC to the detail view but instead just the single managed object that is represented by the selected tableview row.

Apple recommends that the managed object context (MOC) be passed by "dependency injection". This is very simple. In the most common design, you initialize the MOC in the app delegate, then provide each of your view controllers with a managedObjectContext property. Then when you load/push a view controller, you just set it's managedObjectContext property to the MOC.

For example, in a Master-Detail design, you usually have a navigation controller (NAV). To see how this works, create a test app using the navigation based app template in Xcode. Mark it to use Core Data. You will that both the app delegate and the RootViewController have a managedObjectContext property.

Now in the app delegate's applicationDidFinishLaunching:... method add the code to make it look like:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
  // Override point for customization after application launch.
  // Add the navigation controller's view to the window and display.
  RootViewController *topVC=(RootViewController *) self.navigationController.topViewController;
  topVC.managedObjectContext=self.managedObjectContext;
  self.window.rootViewController = self.navigationController;
  [self.window makeKeyAndVisible];
    return YES;
}

... then in the RootViewController.m add:

- (void)viewDidAppear:(BOOL)animated
{
  NSLog(@"self.managedObjectContext = %@",self.managedObjectContext);
  [super viewDidAppear:animated];
}

When you run the test app the RootViewController object will log it's managedObjectContext property something like:

2011-07-19 09:24:05.193 CDNavTemplate[3203:207] self.managedObjectContext = <NSManagedObjectContext: 0x4d318a0>

... proving that the RootViewController object has the managed object context from the app delegate.

Now, you just repeat the process for every view controller you push onto the navigation controllers stack progressively handing the same managed object context object down the view hierarchy. You can pass any other type of object the exact same way.

Apple recommends dependency injection because it makes the code more modular and makes it easy to use multiple managed object context within a single app. You just pass each particular view controller the specific context it needs at any particular time.

like image 67
TechZen Avatar answered Oct 12 '22 10:10

TechZen


In short, there are two options:

  1. Both of these (FetchedResultsController and ManagedObjectContext) need to be in a location where all of the view controllers can access them. For example, if they are in the App Delegate (where Xcode places the ManagedObjectContext by default), you could access it in this manner (this will show a warning - so you'll need to type the delegate to your application's app delegate class):
NSManagedObjectContext *context = [[[UIApplication sharedApplication] delegate] managedObjectContext];
  1. You could actually pass these values into your view controllers when you create them. For example, you could create a subclass (such as DataViewController or something) and have two properties on this subclass (for the ManagedObjectContext and the FetchedResultsController) which would be set when you create them.
like image 45
dtuckernet Avatar answered Oct 12 '22 11:10

dtuckernet