Where to place the "Core Data Stack" in a Cocoa/Cocoa Touch application
IphoneCocoaCocoa TouchCore DataIphone Problem Overview
In the iPhone Core Data Template, Apple places the Core Data Stack in the App Delegate.
My initial inclination however is to move this code into it's own class whose responsibility is to handle the management of the Core Data Stack.
Do you typically encapsulate this functionality within its own class or do you leave it in the App Delegate?
Iphone Solutions
Solution 1 - Iphone
Summary: There is no need to create a singleton to manage the Core Data stack; indeed doing so is likely to be counter-productive.
The Core Data stack happens to be created by the application delegate. Importantly, however, as all the examples show, the stack (principally the managed object context) is not retrieved directly from the stack(*). Instead the context is passed to the first view controller, and from them on a context or a managed object is passed from one view controller to the next (as described in Accessing the Core Data Stack). This follows the basic pattern for iPhone all applications: you pass data or a model controller from one view controller to the next.
The typical role of the singleton as described here is as a model controller. With Core Data, the managed object context is already a model controller. It also gives you the ability to access other parts of the stack if needs be. Moreover, in some situations (as described in the documentation) you might want to use a different context to perform a discrete set of actions. The appropriate unit of currency for a view controller is therefore usually a managed object context, otherwise a managed object. Using and passing a singleton object that manages a stack (and from which you retrieve a context) typically at best introduces a needless level of indirection, and at worst introduces unnecessary application rigidity.
(*) No example retrieves the context using:
[[UIApplication delegate] managedObjectContext];
Solution 2 - Iphone
I have a singleton class that i let do my core data managment and i do not leave it on the app delegate. I rather not clutter the app delegate class with methods i might need for conviniece such as fetching certain objects etc
Solution 3 - Iphone
I leave the core data logic in the App delegate for the following reasons:
-
I do not see any real advantage in moving this code in other classes: the concept of delegation is perfectly fulfilled by the core data logic being handled by the App delegate since the core data model is actually a fundamental part of your application;
-
In all of the sample code I have seen, including Apple samples, the core data stuff is handled by the App delegate;
-
Even in Core Data books it is common practice to have the App delegate handle core data related code;
-
Personally I do not think that readability or anything else is actually improved by having ad hoc classes for core data, but this is a matter of personal taste and I will not argue here what approach is the best one. To me, simplicity while retaining functionality is important.
Solution 4 - Iphone
The question I'd ask myself, in your case, is "who does the Core Data stack 'belong' to?" The data itself is really province of the application, isn't it? (C.F. Core Data on the Mac, where you might have an application capable of working with multiple documents at a time, so the Core Data stack belongs to each document.)
In any Cocoa/Cocoa Touch application, the App Delegate is usually the preferred means of customizing the behavior of the application, so this is the natural place for the Core Data stack.
Now, the problem I suspect you're having is that it feels wrong to constantly write things like:
NSManagedObjectContext *context = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
What I typically do in these cases is write functions (not methods) like this:
NSManagedObjectContext *UIAppManagedObjectContext() {
return [*(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
I write a similar function for the NSPersistentStoreCoordinator
and the NSManagedObjectModel
. I put all of these in the App Delegate's .h/.m files, since these are application-level objects, too.
Solution 5 - Iphone
I'll just list this in a new answer. (I've scrapped my previous FJSCoreDataStack class in favor of this)
My new way of handling this has been to use a category on NSManagedObjectContext. Ive added the following class methods:
+ (NSManagedObjectContext *)defaultManagedObjectContext;
+ (NSManagedObjectContext *)scratchpadManagedObjectContext;
+ (NSManagedObjectModel *)managedObjectModel;
+ (NSPersistentStoreCoordinator *)persistentStoreCoordinator;
+ (NSString *)applicationDocumentsDirectory;
This keeps everything out of my app delegate, and gives singleton access should I choose to use it. However, I still use dependency injection from the App Delegate (as mmalc has said, it introduces inflexibility into my code). I have simply moved all of the "Core Data Stack" code into the NSManagedObjectCOntext Category.
I like passing the reference around, especially since I have a nice "scratchpad context" method. This keeps my View Controllers flexible since I have not committed them to the "defaultManagedObjectContext".
Also relevant to the conversation in the iPhone world (and may have a bearing on your architecture): https://stackoverflow.com/questions/1302181/nsfetchedresultscontroller-and-constructing-nsfetchrequests/1370692#1370692
Solution 6 - Iphone
I'm in favour of having the app delegate know where the model starts, and having the model know where the Managed Object Context is. The Core Data-"ness" of the model seems like an implementation detail of the model to me, the controller classes (like the app delegate) should just ask "give me this information about the model" and the model should know how to answer that question. Therefore having a Core Data object available through a controller object seems like a leaky abstraction.