Franck Verrot

Software Craftsman, Journey Man, Open Source Enthusiast

New Username

| Comments

A couple of days ago I’ve decided to drop my old username CesarioGW to become franckverrot. My GitHub and Twitter accounts have been renamed. I will slowly take care of the remaining accounts.

What Is the Best Way to Pass NSManagedObjectContext Around in iOS Applications?

| Comments

TL;DR Passing an NSManagedObjectContext in each and every NSViewController that needs CoreData can be done by different means, but some are frowned upon. In doubt, inject it.

While pair-reviewing some code with my colleague Vincent Tourraine, we realized we wrote this kind of code into each viewDidLoad: method of each NSViewController subclasses we created:

Please don’t use this snippet in your project - bad.m
1
managedObjectContext = [[[UIApplication sharedApplication] delegate] managedObjectContext];

Doing so is more or less the same as using a global variable, as calling sharedApplication on UIApplication returns the singleton application instance. I kind of felt this was a code smell so I investigated.

After a couple of minute of browsing Apple’s documentation, here’s what we can read

A view controller typically **shouldn’t retrieve** the context from a global object
such as the application delegate. This tends to make the application
architecture rigid. […]
[…]
When you create a view controller, you pass it a context. […]

If you use the good old nib|xibs (I’m acting as if I was confident with them) and instantiate your controllers programmatically, this sounds dead easy, but what if you use the brand new shiny Storyboards?

The only solution I came up with, that will comply with Apple’s recommendation, is to use prepareForSegue, like this:

If you trust me enough, use this code :) - better.m
1
2
3
4
5
6
7
8
9
10
#import "MyMainController.h"
#import "MyOtherController.h"
@implementation MyMainController
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    if([[segue identifier] isEqualToString:@"SegueToMyOtherController"]) {
        MyOtherController *controller = [segue destinationViewController];
        controller.managedObjectContext = managedObjectContext;
    }
}
@end

If your main controller doesn’t have any NSManagedObjectContext, you might want to inject it from within the method application:didFinishLaunchingWithOptions: of your AppDelegate, as you can see if you create a new CoreData project from the templates.

So next time, no more abuse of the sharedApplication !