Recently I came to know that "You really shouldn't be calling down to the AppDelegate to get the managed object context". Apple also has put this recommendation into their documentation here. It goes like this :
A view controller typically shouldn’t retrieve the context from a global object such as the application delegate—this makes the application architecture rigid. Neither should a view controller create a context for its own use (unless it’s a nested context). This may mean that operations performed using the controller’s context aren’t registered with other contexts, so different view controllers will have different perspectives on the data.
Further they have mentioned some other ways to get context. So far I am unable to figure out what they are trying to say there. Can anybody please put some light on the issue. Any code snippet supporting statements would be most welcome.
EDIT
Sometimes, though, it’s easier or more appropriate to retrieve the context from somewhere other than application or the document, or the view controller. Several objects you might use in a Core Data-based application keep a reference to a managed object context. A managed object itself has a reference to its own context, as do the various controller objects that support Core Data such as array and object controllers (NSArrayController and NSObjectController in OS X, and NSFetchedResultsController in iOS).
Retrieving the context from one of these objects has the advantage that if you re-architect your application, for example to make use of multiple contexts, your code is likely to remain valid. For example, if you have a managed object, and you want to create a new managed object that will be related to it, you can ask original object for its managed object context and create the new object using that. This will ensure that the new object you create is in the same context as the original.
What exactly it is? Am sure its not similar with the Highly voted answer below. Can somebody help me to understand this portion of Apple documents?
It is called dependency injection. Basically the caller/constructor should be setting the NSManagedObjectContext
onto the called/constructed.
In your AppDelegate
you should set the NSManagedObjectContext
into the rootViewController
that is associated with the UIWindow
.
Your rootViewController
should then set the NSManagedObjectContext
into the next view controller and so on.
How? It is just a simple proper on the view controller class and the caller uses:
[nextViewController setManagedObjectContext:[self managedObjectContext]];
Some others may recommend a singleton but that is another deep dark pit that is best avoided.
Dependency Injection is the best approach.
It is the approach Apple has designed around. The other choice involves some form of a singleton: AppDelegate or another one.
"The downside of passing the same context between controllers is that if a same entity is modified in two different places, you have to manage the merge conflict."
That is a completely different problem and it is not going to be solved with multiple NSManagedObjectContext
instances. In fact, multiple instances will make the situation worse and guarantee a merge conflict.
In that situation, your view controllers should be listening for changes in the managed object and reacting to them. Making it impossible to update it in two places at once in the UI. The user simply cannot focus on two places at once and therefore the second location will be updated in real time.
That is the right answer for that problem.
Having both entities in the same context will make sure that works correctly. Multiple contexts will cause their to be two objects in memory with the same data and no way to notice the changes without a save to the context.
However, if you are having view controllers that are modifying data without user intervention then you have a separate problem. View controllers are for the user to modify or view data. They are not the place for any kind of background processing of the data.
If you are in an import situation then that is a different question than the one you asked. In that case you are (should be) using multiple threads (UI thread, import thread) and you must have at least one context for each.
In that situation you do risk a merge conflict and you need to code for the situation happening. First step is to change the merge policy on the NSManagedObjectContext
instances.
I suspect you are misreading that documentation.
What that is describing is the ability to get the NSManagedObjectContext
out of the NSManagedObject
instance. This is absolutely useful. Take for example a view controller that has the ability to add or edit an object. By pushing just the NSManagedObject
to the view controller you can control and decide what that view controller is going to be touching. The receiving view controller knows that it needs to allow editing of the received NSManagedObject
. It does not care what NSManagedObjectContext
it is working with. It could be working with the main, it could be working with a child, it could be in isolation in a unit test, it doesn't need to know or care. It simply displays the data from the NSManagedObject
it is handed and saves the associated NSManagedObjectContext
if the user chooses to save the edits.
That documentation is NOT suggesting having some universal location for your NSManagedObjectContext
to live (aka a singleton). It is suggesting that if you have another way to access the NSManagedObjectContext
that is associated with a NSManagedObject
that it is ok to do so and definitely makes sense to do so.