Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing ManagedObjectContext to view controllers using storyboards with a root UITabBarController

Using storyboards you have no easy access to the first view controller in appDelegate (though once you do prepareForSegue makes it easy to pass the ManagedObjectContext down the navigation stack.

I've settled on giving each view controller (or superclass of each view controller) requiring Core Data access a moc member:

@synthesize moc = _moc;
@property (nonatomic) __weak NSManagedObjectContext *moc;

I'm uneasy about it because it doesn't seem a very elegant way to do it - too much code. But assigning directly requires specifying absolute indexes into the viewControllers arrays and changing appDelegate every time the requirement for ManagedObjectContexts change

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;

    // rootView gets a tab bar controller
    for(UINavigationController *navController in tabBarController.viewControllers) {

        for(UIViewController *viewController in navController.viewControllers) {

            if([viewController respondsToSelector:@selector(setMoc:)]) {
                [viewController performSelector:@selector(setMoc:) withObject:self.managedObjectContext];
                NSLog(@"Passed moc to %@", [viewController description]); 
            }
        }
    }

    return YES;
}

What are the pitfalls of this approach and is there a better way? Is it better to try and be more generic:

- (void)assignManagedObjectContextIfResponds:(UIViewController *)viewController {

    if([viewController respondsToSelector:@selector(setMoc:)]) {
        [viewController performSelector:@selector(setMoc:) withObject:self.managedObjectContext];
        NSLog(@"Passed moc to %@", [viewController description]); 
    }

}
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    NSMutableArray *viewControllers = [NSMutableArray array];

    UIViewController *firstLevelViewController = self.window.rootViewController;

    if([firstLevelViewController respondsToSelector:@selector(viewControllers)]) {

        NSArray *firstLevelViewControllers = [firstLevelViewController performSelector:@selector(viewControllers)];

        for(UIViewController *secondLevelViewController in firstLevelViewControllers) {

            if([secondLevelViewController respondsToSelector:@selector(viewControllers)]) {

                NSArray *secondLevelViewControllers = [secondLevelViewController performSelector:@selector(viewControllers)];

                for(UIViewController *thirdLevelViewController in secondLevelViewControllers) {

                    [viewControllers addObject:thirdLevelViewController];
                }

            } else {
                [viewControllers addObject:secondLevelViewController];
            }
        }
    } else {
        // this is the simple case, just one view controller as root
        [viewControllers addObject:firstLevelViewController];
    }

    // iterate over all the collected top-level view controllers and assign moc to them if they respond
    for(UIViewController *viewController in viewControllers) {
        [self assignManagedObjectContextIfResponds:viewController];
    }

    return YES;
}
like image 469
Adam Eberbach Avatar asked Feb 28 '12 04:02

Adam Eberbach


1 Answers

Don't know if I understood properly, but why don't you left the managed object context directly in AppDelegate class and leave there all the logic for instantiate. And from then you can ask for it.

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;

then you can recall it anytime from anywhere.

NSManagedObjectContext *moc = [(YourApplicationDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];

For convenience I declared a define for it:

#define MOC [(YourApplicationDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext]

Therefore this become:

[MOC save:&error];

You can take this everywhere you like. Just try to have a look at the auto generated code for a CoreData application in Xcode, you will see that many accessors with CoreData are in there, and the CoreData itself is lazily initialized at first request.

like image 68
Leonardo Avatar answered Oct 16 '22 21:10

Leonardo