Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sharing Managed Object Context

I'm writing a test program that use a Tab Controller with multiple tab views. The program downloads multiple XML files, parses and populates sqlite tables through Core Data. The Core Data variables and functions are in the App Delegate file following the Xcode created code.

I started by simply passing the managedObjectContext variable to each subview that needed it, as I initialized it in the App Delegate, e.g.:

FirstViewController *vc1;
vc1 = [[[FirstViewController alloc] initWithNibName:@"FirstView" bundle:nil] autorelease];
[vc1 setManagedObjectContext:self.managedObjectContext];

However, I have a function (resetData) that deletes the entire data store--deletes the persistent store files and sets all the Core Data variables (managedObjectContext, managedObjectModel, persistentStore, etc) to nil, reinitializing everything. This is so that the program can start from scratch and redownload all of the data from the network. When this happens, the subviews now point to the old managedObjectContext.

What's the best way to update the managedObjectContext variable in all the subviews? Manually update the subviews' managedObjectContext variables from the resetData function? Use NSNotificationCenter to send a notification to all views? Is completely deleting and reinitializing all the persistent store files overkill?

I currently have put this getter that just refers back to the App Delegate in all the classes that need to refer to the MOC:

- (NSManagedObjectContext *)managedObjectContext {
    MyAppDelegate* ad = (MyAppAppDelegate*)[[UIApplication sharedApplication] delegate];
    return [ad managedObjectContext];
}

I'm very new to Cocoa / iOS design patters am trying to figure out the most proper way to do these things! What I've got now works, but I wonder if there are unseen pitfalls or future problems? Thanks!

like image 449
Raolin Avatar asked Dec 10 '25 19:12

Raolin


2 Answers

IMHO passing the managedObjectContext into the ViewControllers is good practice. It makes testing easier and creates better reusable ViewControllers.

One way to achieve the desired result would be to simply delete all objects from the store, while leaving the CoreData Stack intact. All view controllers would simply use the same context as before, but it does not contain objects anymore. But that might be to slow, depending on the number of objects.

The fastest and most efficient way to delete all objects is indeed to remove the storage file. NSManagedObjectContext offers a setter for the persistent store coordinator. Have you tried to create a new storeCoordinator with a new file, set it as the storeCoordinator of your MOC and then release the old coordinator and delete the old file? You might need to send a Notification is this case, as all ViewControllers have to release their potentially retained managedObjects.

Another idea, that just came to my mind, and that I have used before is to completely remove the complete viewController stack and then recreate it using the new managedObjectContext. You could easily download, parse and save the new data into it's own separate managedObjectContext (featuring it's own persistentStoreController and own store)in the background. Once that is finished, remove all controller from the window, keeping track of with controllers were shown. Then move the new store file overwriting the old one and recreate the viewController stack as it was before. While that sounds like an expensive operation, it is not. In my case the switch wasn't even noticeable in the UI. The advantage over keeping the viewControllers is, that it is by far less likely, that old managedObjects are still lurking around somewhere, thus leading to less code requiring additional editing. If your viewControllers are already set up the way apple recommends chances are good that this switch will "just work".

like image 194
tonklon Avatar answered Dec 13 '25 08:12

tonklon


There are no best way but good implementations. Your last solution accessing always to the context through the app delegate is good. Remember that in that case you cannot use the instance variable if it is synthed.

I suppose that your objects need to know when the persistent data has been reseted and so they are using a new context. You can use a instance variable to check it:

@synthesize managedObjectContext = moc_ ;

Then you can test:

- (NSManagedObjectContext *)managedObjectContext {
    MyAppDelegate* ad = (MyAppAppDelegate*)[[UIApplication sharedApplication] delegate];

    if(moc_ != [ad managedObjectContext]) {
          // NEW CONTEXT. DO ANYTHING NEEDED TO RESET OBJECT
    }

    // Use property to change value to ensure set rules (retain for example).
    [self setManagedObjectContext:[ad managedObjectContext]];

    return moc_;
}
like image 44
Gabriel Avatar answered Dec 13 '25 08:12

Gabriel



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!