Core data 将ManagedObjectContext传递给使用带有根UITabBarController的情节提要的视图控制器

Core data 将ManagedObjectContext传递给使用带有根UITabBarController的情节提要的视图控制器,core-data,ios5,uinavigationcontroller,uitabbarcontroller,uistoryboard,Core Data,Ios5,Uinavigationcontroller,Uitabbarcontroller,Uistoryboard,使用故事板,您无法轻松访问appDelegate中的第一个视图控制器(尽管一旦执行prepareforsgue操作,就可以轻松地将ManagedObjectContext向下传递到导航堆栈中 我已经决定给每个需要核心数据访问的视图控制器(或每个视图控制器的超类)一个moc成员: @synthesize moc = _moc; @property (nonatomic) __weak NSManagedObjectContext *moc; 我对此感到不安,因为这似乎不是一种非常优雅的方式——代

使用故事板,您无法轻松访问appDelegate中的第一个视图控制器(尽管一旦执行
prepareforsgue
操作,就可以轻松地将ManagedObjectContext向下传递到导航堆栈中

我已经决定给每个需要核心数据访问的视图控制器(或每个视图控制器的超类)一个moc成员:

@synthesize moc = _moc;
@property (nonatomic) __weak NSManagedObjectContext *moc;
我对此感到不安,因为这似乎不是一种非常优雅的方式——代码太多。但直接赋值需要在ViewController数组中指定绝对索引,并在每次ManagedObjectContext的要求发生变化时更改appDelegate

- (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;
}
这种方法的缺点是什么?是否有更好的方法?是否最好尝试更通用:

- (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;
}

我不知道我是否理解正确,但为什么不直接将托管对象上下文留在AppDelegate类中,并将实例化的所有逻辑留在那里。从那时起,您就可以请求它了

@property (readonly, strong, nonatomic) NSManagedObjectContext *managedObjectContext;
然后你可以随时随地回忆起它

NSManagedObjectContext *moc = [(YourApplicationDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext];
为了方便起见,我为它声明了一个定义:

#define MOC [(YourApplicationDelegate*)[[UIApplication sharedApplication] delegate] managedObjectContext]
因此,这成为:

[MOC save:&error];
你可以把这个带到任何你喜欢的地方。 只要看看Xcode中CoreData应用程序的自动生成代码,就会发现其中有许多具有CoreData的访问器,并且CoreData本身在第一次请求时被延迟初始化。

Adam

当我在探索故事板的时候,我几乎和你们一样,只是我让每个具有MOC属性的视图控制器都符合协议

那里没有什么明显的不同,所以我继续

我认为关键是故事板,依我看,是半生不熟的。来自.Net的背景,明显缺少的是一个对象生成器框架和一个IoC容器。 当苹果公司添加这个故事板时,它将非常棒。当故事板框架可以查看destinationViewController时,确定它的依赖项并从容器生命中解决这些依赖项将非常棒。现在,它真正能做的就是查看destinationViewController,并为您初始化一个通用的,用途有限的

不幸的是,因为这是一个半生不熟的解决方案,我现在坚持使用传统的方法,所以我所有的视图控制器都是手动分配和初始化的,更重要的是,我为每个视图控制器添加了一个方法initWithMOC:(MOC*)MOC

我内心的架构师告诉我,这段代码更健壮,我想这是一个关于它是否值得权衡的意见问题

还有人想出更好的办法吗


CA.

我知道你可以这样做,但我正在努力避免。我无法清楚地说明为什么它是错误的,但感觉是这样的,#到处导入AppDelegate。这没有错,这是一种方法,当你可以轻松访问上下文时,传递上下文是没有意义的。导入仅用于避免编译器警告(而不是错误),因为您可以随时调用[UIApplication sharedApplication]这也是Xcode为CoreData应用程序生成的,我很惊讶为什么你说这是错误的,并且更喜欢以这种方式传递上下文。通过集中CoreData访问器,你还可以更好地控制保存错误、延迟加载,无论你喜欢什么。“错误”可能不是正确的词。我正在寻找最优的。答案如下:
嵌套上下文使得采用“传递接力棒”方法访问上下文变得比以往任何时候都重要(通过将上下文从一个视图控制器传递到下一个视图控制器)而不是直接从应用程序委托中检索它。
从这里确定,这是与嵌套上下文相关的,只有一个上下文,从AppDelegate获取它是足够安全的。