CoreData UITableViewController 管理对象上下文错误。

4

我已经开始尝试使用CoreData,并将其基础应用到自己的项目中。我已经基本上复制了一个新项目,但是我遇到了一个错误。

这行代码 controller.managedObjectContext = self.managedObjectContext; 导致了问题。当我注释它时,应用程序只会启动一个空的UITableView,但是如果我包含这行代码,就会导致以下错误:

Universal[24718:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITableViewController setManagedObjectContext:]: unrecognized selector sent to instance 0x1521a0'
*** First throw call stack:
(0x344558bf 0x346a51e5 0x34458acb 0x34457945 0x343b2680 0x2413 0x378367eb 0x378303bd 0x377fe921 0x377fe3bf 0x377fdd2d 0x30c30df3 0x34429553 0x344294f5 0x34428343 0x343ab4dd 0x343ab3a5 0x3782f457 0x3782c743 0x2331 0x22c8)
terminate called throwing an exception

如果需要查看更多代码,我可以提供,希望你能理解发生的情况。我没有发现会导致这种情况的任何问题,也没有收到任何错误信息,但是当该行代码被执行时,整个应用程序就会崩溃,我不知道原因。
该行代码位于应用程序委托的didFinishLaunchingWithOptions方法中,就像在一个新的core data项目中一样。
按照要求,以下是表视图控制器的头文件:
#import <UIKit/UIKit.h>

#import <CoreData/CoreData.h>

@interface myTableViewController : UITableViewController <NSFetchedResultsControllerDelegate>

@property (strong, nonatomic) NSFetchedResultsController *fetchedResultsController;
@property (strong, nonatomic) NSManagedObjectContext *managedObjectContext;

@end

请展示controller类的头文件。 - Jim
4个回答

6
你遇到错误的原因在于你的AppDelegate.m文件中。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
    MasterViewController *controller = (MasterViewController *)navigationController.topViewController;
    controller.managedObjectContext = self.managedObjectContext;
    return YES;
}

使用默认的CoreData模板时,托管对象上下文被分配给顶层视图控制器,而您已插入不同的视图作为起始点,因此会出现“未识别的选择器发送到实例”的错误。
您有两个选项:
1)删除分配托管对象上下文的代码,在需要它的视图中像这样获取它:
 [[[UIApplication sharedApplication] delegate] mainManagedObjectContext];

2) 保留代码(更正类名),为managedObjectContext添加声明,并在您的所有UIViewControllers之间传递NSManagedObjectContext对象,以便在整个应用程序中使用。


通过应用程序委托单例共享托管对象上下文通常被称为反模式,这使得架构变得僵硬。在大多数实现中不应该鼓励这种做法。 - tzuchien.chiu
2
@tzuchien.chiu,要么创建自己的答案来展示正确的模式,要么链接到一个能够展示正确模式的文章会更有帮助。 - Tom

2

在你提供的教程中,我进行了一些小的调整。我还愚蠢地忘记在Interface Builder中设置视图的类。然而,如果我的表视图控制器是根视图,那么这个方法是有效的。但是,如果我想要在更深层次上访问它怎么办?我需要更改其中一行代码,对吗? UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController; guestListMasterViewController *controller = (guestListMasterViewController *)navigationController.topViewController; controller.managedObjectContext = self.managedObjectContext; - Josh Kahane
是的,您需要在正确的UIViewController上设置managedObjectContext。鉴于您发布的代码量,我无法告诉您确切的操作方法,但您已经接近成功了。 - occulus
我提供的代码设置了我想要的视图的managedObjectContext,但不在正确的位置,因为它不是topViewController。所以我不确定如何获取此视图的上下文,无论其层次结构如何。 - Josh Kahane

2

这取决于你的应用程序的结构。如果你在所有代码前面使用了TabBarViewController,那么代码会有所不同。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    UITabBarController *tabController = (UITabBarController *)self.window.rootViewController;

    UINavigationController *navigationController = (UINavigationController *)[[tabController viewControllers] objectAtIndex:0];
    MasterViewController *controller = (MasterViewController *)[[navigationController viewControllers] objectAtIndex:0];
    controller.managedObjectContext = self.managedObjectContext;

    return YES;
}

1

我曾经遇到过同样的问题,但最终解决了。我的方法是确保在根视图控制器(即第一个与第一个导航控制器相连接的视图控制器)中包含ManagedContextObject属性,即使它可能不会使用它。

在根视图控制器的.h文件中:

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;

在 .m 文件中

@synthesize managedObjectContext;

如果我的回答有点简单了,那我向你道歉。为了让自己理解,我必须把事情说得简单明了 :)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接