【问题标题】:Passing a ManagedObjectContext to a second view将 ManagedObjectContext 传递给第二个视图
【发布时间】:2010-11-07 15:42:37
【问题描述】:

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

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

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

- (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:找不到实体名称“SecondEntity”的 NSManagedObjectModel”

【问题讨论】:

  • 将初始化获取结果控制器的代码放入 viewDidLoad 会发生什么?我有一个应用程序基本上做同样的事情,它对我来说很好,但我直接在 viewDidLoad 中使用 initWithFetchRequest:managedObjectContext:sectionNameKeyPath:cacheName: 创建我的获取结果控制器。
  • @Tim 我刚试过,它以同样的方式崩溃。奇怪的是,如果我设置一个断点,self的所有成员变量都是NULL,但标题确实设置正确,所以这不可能是真的。

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


【解决方案1】:

您可以通过先强制转换您的应用程序委托来抑制协议警告中未找到的“-managedObjectContext”:

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

【讨论】:

    【解决方案2】:

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

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

    google上有很多关于viewDidLoad多次执行的问题的参考,所以我认为解决的办法是不在viewDidLoad中做这个fetch请求初始化。

    【讨论】:

      【解决方案3】:

      我一直在为同样的问题而苦苦挣扎,但我还是个新手。我想我知道发生了什么。让我知道这是否有意义。

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

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

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

      这应该可以解决问题。

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

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

          但是,如果这是一个主列表 -> 详细视图类型交互,我建议将所选对象直接传递给第二个视图控制器,而不是只给它“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.
          }
          ...
          

          【讨论】:

          • 是的,实体存在。不是master list->detail..更像是category->items,我希望能直接和data store交互,因为第二个view真的是主交互屏,所以不想随便将快照传递给第二个视图。
          【解决方案6】:

          只是为了好玩..尝试替换:

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

          与:

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

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

          【讨论】:

          • 有趣。我回家后会试试这个。
          • 这是否意味着 self.title = tName 也是错误的形式?
          • 一点也不。虽然我不确定 tName 来自哪里。 Objective C 中的点语法 is 调用您的访问器方法,即使它可能似乎 正在命中 ivars。
          【解决方案7】:

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

          之前:

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

          之后:

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

          嗯。菜鸟错误。

          【讨论】:

            【解决方案8】:

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

            尝试更改代码

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

            有了这个

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

            【讨论】:

              【解决方案9】:

              这可能是问题所在。

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

              长答案:

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

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

              要修复它,请删除您的应用。这将删除保存的模型,当您再次运行它时,它将重新创建您的新模型。

              【讨论】:

                【解决方案10】:

                有一件事是肯定的,这行: secondViewController.managedObjectContext = [self managedObjectContext];

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

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

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-04-27
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多