将ManagedObjectContext传递给第二个视图

时间:2009-07-02 14:02:16

标签: iphone objective-c cocoa-touch core-data

我正在编写我的第一个iPhone / Cocoa应用程序。它在导航视图中有两个表视图。当您触摸第一个表视图中的行时,您将进入第二个表视图。我希望第二个视图显示与您在第一个视图中触摸的行相关的CoreData实体的记录。

我在第一个表视图中显示的CoreData数据很好。您可以触摸一行并转到第二个表格视图。我能够将所选对象的信息从第一个视图传递到第二个视图。但我无法获得第二个视图来进行自己的CoreData获取。对于我的生活,我无法将managedObjectContext对象传递给第二个视图控制器。我不想在第一个视图中执行查找并传递字典,因为我希望能够使用搜索字段在第二个视图中优化结果,以及从那里向CoreData数据插入新条目。 / p>

这是从第一个视图转换到第二个视图的函数。

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Navigation logic may go here -- for example, create and push another view controller.
    NSManagedObject *selectedObject = [[self fetchedResultsController] objectAtIndexPath:indexPath];
    SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondView" bundle:nil];

    secondViewController.tName = [[selectedObject valueForKey:@"name"] description];
    secondViewController.managedObjectContext = [self managedObjectContext];

    [self.navigationController pushViewController:secondViewController animated:YES];
    [secondViewController release];
}

这是SecondViewController中崩溃的函数:

- (void)viewDidLoad {
    [super viewDidLoad];

    self.title = tName;

    NSError *error;
    if (![[self fetchedResultsController] performFetch:&error]) { // <-- crashes here
        // Handle the error...
    }
}

- (NSFetchedResultsController *)fetchedResultsController {

    if (fetchedResultsController != nil) {
        return fetchedResultsController;
    }

    /*
     Set up the fetched results controller.    
     */
    // Create the fetch request for the entity.
    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
    // Edit the entity name as appropriate.
        // **** crashes on the next line because managedObjectContext == 0x0
    NSEntityDescription *entity = [NSEntityDescription entityForName:@"SecondEntity" inManagedObjectContext:managedObjectContext]; 
    [fetchRequest setEntity:entity];

    // <snip> ... more code here from Apple template, never gets executed because of the crashing

    return fetchedResultsController;
}

关于我在这里做错了什么的想法?

managedObjectContext是一个保留属性。

更新:我插入了一个NSLog([[managedObjectContext registeredObjects] description]);在viewDidLoad中,看来managedObjectContext传递得很好。但是仍在崩溃。

由于未捕获的异常'NSInternalInconsistencyException'而终止应用程序,原因:'+ entityForName:无法找到实体名称的'NSManagedObjectModel''SecondEntity''

10 个答案:

答案 0 :(得分:18)

您可以通过首先强制转换应用程序委托来禁止在协议警告中找不到'-managedObjectContext':

if (managedObjectContext == nil) { managedObjectContext = [(MyAppDelegateName *)[[UIApplication sharedApplication] delegate] managedObjectContext]; }

答案 1 :(得分:7)

哦,这很有趣。我花了一些时间在堆栈跟踪上,我想我已经弄明白了。

因此pushViewController不会调用viewDidLoad一次,而是两次。第一次调用viewDidLoad时,对象似乎没有被正确实例化。第二次,他们是。因此,第一次运行此代码时,它无法访问managedObjectContext,并引发异常。它第二次运行,一切都很好。没有崩溃。

有很多关于viewDidLoad在Google上执行多次的问题的引用,所以我认为解决方法是不在viewDidLoad中执行此获取请求初始化。

答案 2 :(得分:1)

我一直在努力解决同样的问题而且我还只是一个新手。我想我弄清楚发生了什么。如果这是有道理的,请告诉我。

简而言之,您正在尝试从尚未设置的objectContext中获取实体。因此,您的选项是在此视图加载之前立即设置或在应用程序的其他位置进行设置。

如果您的应用程序设置为来自iphone开发中心的CoreDataBooks应用程序演示,主要的UIApplicationDelegate也管理CoreData堆栈,那么您应该能够执行以下操作:

if (managedObjectContext == nil) { managedObjectContext = [[[UIApplication sharedApplication] delegate] managedObjectContext]; }

这应该可以解决问题。

答案 3 :(得分:1)

在您的第一个tableViewController中,您可以通过managedObjectContext传递secondTableController.managedObjectContext = [(AppDelegate *) [[UIApplication sharedApplication ] delegate ] managedObjectContext ],也许没关系

答案 4 :(得分:0)

你确定有一个名为“SecondEntity”的实体吗? (这将是解释错误消息的直接方式。)

但是,如果这是主列表 - &gt;详细视图类型交互,我建议将所选对象直接传递给第二个视图控制器,而不是只给它“tname”。该对象可能包含通过其属性直接填充第二个表所需的所有内容。

这样,您实际上不会在第二个视图控制器中进行任何显式提取。即:

@interface SecondViewController : UITableViewController
@property (nonatomic, retain) NSManagedObject *selectedObject;
@end

@implementation SecondViewController
- (void)viewDidLoad
{
    NSMutableArray *stuff = [[[selectedObject valueForKey:@"aToManyRelationship"] allObjects] mutableCopy];
    // sort stuff the way you want to display them, etc.
}
...

答案 5 :(得分:0)

只是为了踢...尝试替换:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"SecondEntity" inManagedObjectContext:managedObjectContext]; 

使用:

NSEntityDescription *entity = [NSEntityDescription entityForName:@"SecondEntity" inManagedObjectContext:[self managedObjectContext]]; 

您正在通过setter设置managedObjectContext,然后尝试直接访问ivar。根据您的属性的定义方式,这可能不正确。 [self managedObjectContext]将尝试通过getter访问该值,而不是直接访问。

答案 6 :(得分:0)

我遇到了这个问题,发现我的对象的init消息在调用setManagedObjectContext之前访问了managedObjectContext ...

在:

 dataController = [[DataController alloc] init];
 [dataController setManagedObjectContext:[self managedObjectContext]];

之后:

 dataController = [DataController alloc];
 [dataController setManagedObjectContext:[self managedObjectContext]];            
 [dataController init];

FEH。菜鸟错误。

答案 7 :(得分:0)

Apple提供了一个名为“iPhoneCoreDataRecipes”的示例项目。有一篇关于传递NSManagedObjectContext here的非常有趣的文章 如果你试图实现这种逻辑,每个managedObjectContext在每个UIViewController中都是一个独立的岛

尝试更改代码

if (managedObjectContext == nil) { managedObjectContext = [(MyAppDelegateName *)[[UIApplication sharedApplication] delegate] managedObjectContext]; }

有了这个

if (managedObjectContext == nil) { managedObjectContext = self.managedObjectContext }

答案 8 :(得分:-1)

这可能是问题所在。

简短回答:删除您的应用,然后再次运行。

答案很长:

如果您构建并运行项目,CoreData会将您的模型保存到您所说的任何位置(持久存储位置)。

如果您在CoreData模型中更改某些内容,则当您再次运行该应用时,新模型将与保存的模型不匹配,从而导致该错误。

要解决此问题,请删除您的应用。这将删除已保存的模型,当您再次运行它时,它将重新创建您的新模型。

答案 9 :(得分:-2)

有一点可以肯定,这条线:   secondViewController.managedObjectContext = [self managedObjectContext];

应该是:   secondViewController.managedObjectContext = self.managedObjectContext;

除非当前对象实现了一个名为'managedObjectContext'的方法,该方法返回该变量。