我知道如何解决这个问题,但是我不理解为什么这不起作用。我有一个使用Core Data的UIViewController子类,因此它需要NSManagedObjectContext。控制器从一个nib文件加载,它位于一个选项卡控制器内的导航控制器下。
我尝试在initWithCoder和viewDidLoad中执行此操作,但由于某种原因它不起作用:
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = [[appDelegate managedObjectContext] retain];
由于某种原因,managedObjectContext返回nil,当我稍后尝试创建托管对象时,我得到了这个:
***由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'+ entityForName:无法在此模型中找到名为'LogRecord'的实体。'
当您的上下文为零或无法加载模型(或实际上缺少实体)时,您获得的是什么。
如果我在saveLogEntry方法的顶部执行完全相同的操作(创建托管对象并保存上下文),那么它的工作正常。
如果我执行Recipes示例应用程序所做的事情:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
loggingViewController.managedObjectContext = self.managedObjectContext;
// Standard stuff
[window addSubview:tabBarController.view];
[window makeKeyAndVisible];
}
(loggingViewController是app委托中的IBOutlet)。
有谁知道这里可能会发生什么?如果“太早”完成它似乎失败了,但特别是对于viewDidLoad我希望它能够工作,因为我认为这是在调用addSubview之后发生的。
答案 0 :(得分:6)
完全按照食谱应用程序执行的操作。
如果你在initWithCoder中尝试它,你不知道应用程序委托是否已完成初始化(它没有完成)
如果你试试viewDidLoad,你就会遇到类似的问题。
这就是为什么你应该不这样访问app delegate:
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
self.managedObjectContext = [[appDelegate managedObjectContext] retain];
这是不好的形式。它将耦合引入您的设计中。使用依赖注入,就像示例一样。它使您的应用程序更加灵活。
因为从app委托中你确切地知道已经执行了什么初始化,并且可以在适当的时间传递上下文。
<强>更新强>
问题是您的View Controller实例很可能在Mainwindow.xib中实例化。 Mainwindow.xib(以及它引用的任何其他nib)在app委托收到UIApplicationDidFinishLaunchingNotification通知之前被“解冻”。
无法保证对象从笔尖解冻的顺序。当您在View Controller上调用initWithCoder:时,您不知道其他对象是否已从nib解冻。您也无法确定应用代表是否收到了UIApplicationDidFinishLaunchingNotification通知。
viewDidLoad类似。在viewDidLoad中,您可以确保nib中的所有其他对象都已正确解冻和初始化,但由于应用程序委托的配置发生在nib文件之外,因此您无法确定是否可以安全地调用该应用程序委派。
最好让app delegate在“良好且准备好”的情况下在上下文中传递,最好是在applicationDidFinishLaunching:方法中。
希望有点清楚,你应该看一下iphone编程指南: http://developer.apple.com/iphone/library/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/index.html
收集有关iPhone应用程序生命周期的更好解释。
希望有所帮助。
更多更新:
深入讨论iphone发布顺序: http://www.bit-101.com/blog/?p=2159