核心数据 - 关系意外地变为零

时间:2011-07-31 07:23:15

标签: core-data nsmanagedobjectcontext

我正在努力应对Core Data中的一些奇怪行为。我有一个相当标准的设置,使用CoreDataBook示例:我有一个RootView,它使用NSFetchedResultsController来显示Items列表。 Item具有一些属性和与其他实体的关系。我有一个DetailView,我用它来创建一个新的Item,以及编辑一个现有的Item,我以模态方式呈现。在DetailView:viewDidLoad中,我创建了一个新的managedObjectContext,我想在其中进行所有更改...如果用户按下Save,我保存此上下文并合并更改;否则,如果用户按下取消,则所有这些更改都会消失。

“添加新项目”部分工作正常,但是当我选择行以显示与现有项相同的DetailView时,其中一个关系(在调试器的RootView中显示正常)突然变为零当它出现在DetailView中时。这是在UITableView的didSelectRowAtIndexPath中显示DetailView的代码:

    Item *managedObject = (Item *)[self.fetchedResultsController objectAtIndexPath:indexPath];
    DetailView *childController = [[DetailView alloc] initWithNibName:@"DetailView" bundle:nil];

    UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:childController];    

    childController.existingItem = managedObject;

    // ** Item's relationship to Title is not nil at this point
    [self presentModalViewController:navController animated:YES];
    // ** Item's relationship Title is now nil

    [childController release];
    [navController release];

在DetailView控制器中没有什么特别的东西可以导致这种情况。事实上,它甚至没有机会真正对任何损害......一旦启动,现有的Item.title关系已经是零。 [existingItem是DetailView的保留属性]

我知道应该从哪里开始研究这个问题吗?在过去的几个小时里,它一直让我发疯。这是DetailView viewDidLoad中的一些代码,但是在它被调用之前它的关系是nil:

    // Create a new managed object context
    NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] init];
    self.addEditContext = addingContext;
    [addingContext release];
    [self.addEditContext setPersistentStoreCoordinator:[[appDelegate managedObjectContext] persistentStoreCoordinator]];

    if (!self.existingItem) {
        self.existingItem = [NSEntityDescription insertNewObjectForEntityForName:@"Item" inManagedObjectContext: self.addEditContext];

    }else{
        self.existingItem = (Item *)[self.addEditContext objectWithID:[self.existingItem  objectID]];
    }

通过从某个列表中选择来设置标题关系:

self.existingItem.title = selectedTitle;

在save:方法中,我保存addEditContext并将更改与appdelegate上下文合并:

    NSNotificationCenter *dnc = [NSNotificationCenter defaultCenter];
    [dnc addObserver:self selector:@selector(addControllerContextDidSave:) name:NSManagedObjectContextDidSaveNotification object: self.addEditContext];

    // Save the context.
    NSError *error = nil;
    if (![self.addEditContext save:&error]){
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    }

    [dnc removeObserver:self name:NSManagedObjectContextDidSaveNotification object:self.addEditContext];
    self.addEditContext = nil;

在addControllerContextDidSave中:

- (void)addControllerContextDidSave:(NSNotification*)saveNotification {
    id appDelegate = [[UIApplication sharedApplication] delegate];
    // Merging changes causes the fetched results controller to update its results
    [[appDelegate managedObjectContext] mergeChangesFromContextDidSaveNotification:saveNotification];   
}

因此save:stuff适用于新Item,但是当该Item设置为existingItem并再次加载时,self.existingItem.title为nil。它从视图控制器中显示的位置开始是零(即使它在呈现之前不是零)。所以在主上下文中,它加载Item和它的标题关系很好,但是当它在presentModalViewController:navController中呈现时标题突然消失。

真奇怪。如果有人能够对此有所了解,那将非常感激。

更新:另外需要提及的是标题肯定存在于persistentStore中。每次我关闭并重新加载应用程序时,RootView都会显示正在设置的标题关系。一旦我选择了行,关系就变为零。

1 个答案:

答案 0 :(得分:1)

你的设计都是不必要的复杂和冗余。我认为这种关系显示为零,因为你的self.existingItem属性分配了错误的类。

首先,没有理由为同一个前台线程上的另一个视图创建另一个上下文。只需将现有的上下文传递给下一个视图,就可以省去合并到上下文的麻烦,无需任何功能。

其次,这个块:

}else{
    self.existingItem = (Item *)[self.addEditContext objectWithID:[self.existingItem  objectID]];
}

...完全没有意义,因为您正在为自己设置self.existingItem。你可能也写过:

self.existingItem = self.existingItem;

...因为一旦保存了对象,就会在持久存储中修复对象ID。如果该对象尚未保存,则该ID是临时的,而其他上下文无论如何都无法找到它。

问题的最可能原因是existingItem属性的定义。如果您将其定义为idNSManagedObject,则它将不会响应title选择器并返回nil。它会出错,但你把它转换为Item,所以编译器认为它将响应Item对象的所有消息。

除非你知道你会强迫某个物体模仿另一个物体,否则不要使用石膏。否则,您只是创建了隐藏编译器错误的机会。