views:

2106

answers:

6

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?

+11  A: 

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

Daniel
Sounds practical to me. I'm surprised apple includes it the app delegate.
Corey Floyd
they probably do that because they want to show how to do it and thats where they though it would be convienient place to put it since the app delegate is sort of a singleton already
Daniel
having a singleton core data controller object makes totally sense.we have it abstracted so that it can be reused in every project. +1
stigi
I also use a singleton class for the Core Data stack right now. I see it as acting like the notification center or shared user defaults, where you can call [[DatabaseController sharedDatabaseController] writableManagedObjectContext] to grab a specific context when needed. It seems clunky to call back to the application delegate to grab the stack.
Brad Larson
I was thinking of using a singleton although I try to avoid them. Of course the app delegate is basically a singleton anyways, it just has a clunky method call. I also thought it would be convenient to have a class I can just drop in a any app when I want core data. Seems more OOP-like than adding methods/ivars to the app delegate. Good answers from "both sides of the street" so far.
Corey Floyd
I agree with (a) having a generic core data management class that is much easier to drop into projects (especially ones already existing) and (b) that the reason it's always in the AppDelegate for examples is that they are trying to minimize as much non-example code as possible - so why make a whole singleton when the AppDelegate behaves that way for free (in terms of code length). I'd put it in a singleton so that only the classes dealing with Core Data had any contact with the singleton, and it also means fewer classes have to include the App Delegate header too.
Kendall Helmstetter Gelner
+6  A: 

I leave the core data logic in the App delegate for the following reasons:

1) 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;

2) In all of the sample code I have seen, including Apple samples, the core data stuff is handled by the App delegate;

3) Even in Core Data books it is common practice to have the App delegate handle core data related code;

4) 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.

unforgiven
I usually see the Core Data stack in the App Delegate as well. However, the code I look at is usually created for illustrative purposes. The practical way to implement something sometimes differs from such examples. I didn't want to blindly follow Apples sample code without good reason. I tend to think you are correct in assuming it will just be a matter of personal taste with a few advantages either way.
Corey Floyd
I also think that arguments 2 and 3, are because in tutorials or examples you are trying to minimize as much as possible any code not related to what you are trying to present - so implementing the mechanics of a Singleton is adding too much overhead to what is supposed to be a simple example. The thing I dislike about keeping these things in the App Delegate, is that it increases the number of things that then must know about the App Delegate...
Kendall Helmstetter Gelner
+6  A: 

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.

Alex
Thats funny. That is exactly the piece of code I don't like. I dislike running to the App Delegate for file storage information. It felt "wrong". That made me question how other developers handled this situation.
Corey Floyd
The reason the first code snippet feels wrong is because its a code smell. Wrapping that up in a handy function is just deodorant. Its a lot more straightforward to simply pass the context around to objects that need it (using property injection, mostly).
Luke Redpath
+2  A: 

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.

Graham Lee
Something that has become an issue in iPhone development is using and configuring NSFetchedResultsControllers. You can also have your "Model" now how to configure and return NSFetcheResultsControllers, but it seems like the model class will get a bit bloated. I feel like NSFetchedResultsControllers blur the line between controller and model code (not necessarily in a bad way). I have recently taken this and some other ideas into my new configuration (added new answer).
Corey Floyd
+2  A: 

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): http://stackoverflow.com/questions/1302181/nsfetchedresultscontroller-and-constructing-nsfetchrequests/1370692#1370692

Corey Floyd
+9  A: 

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];
mmalc
Not using dependency injection was definitely a bad design when I first began using Core Data. Recently, I take about the same approach as you have outlined. The primary difference is that I have put the Core Data Stack Code in a category on NSManagedObject Context, if only to logically separate the Core Data stack code from the AppDelegate. In theory, I could use the category like a singleton, but I choose not to as it introduces "application rigidity" as you have said. Additionally, I use some custom code for the Core Data stack, and this allows me to drop this code into new projects easily.
Corey Floyd
I am with you on using the App Delegate for creating the Core Data stack. I am using a UITabBarController as my root view controller, and I'm not sure how to propagate the context to that controller object, as it lives in MainWindow.xib and I'm not sure how to assign it a pointer to a ManagedObjectContext.. I think I'm posting a separate question for this.
mvexel