我正在努力应对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都会显示正在设置的标题关系。一旦我选择了行,关系就变为零。
答案 0 :(得分:1)
你的设计都是不必要的复杂和冗余。我认为这种关系显示为零,因为你的self.existingItem
属性分配了错误的类。
首先,没有理由为同一个前台线程上的另一个视图创建另一个上下文。只需将现有的上下文传递给下一个视图,就可以省去合并到上下文的麻烦,无需任何功能。
其次,这个块:
}else{
self.existingItem = (Item *)[self.addEditContext objectWithID:[self.existingItem objectID]];
}
...完全没有意义,因为您正在为自己设置self.existingItem
。你可能也写过:
self.existingItem = self.existingItem;
...因为一旦保存了对象,就会在持久存储中修复对象ID。如果该对象尚未保存,则该ID是临时的,而其他上下文无论如何都无法找到它。
问题的最可能原因是existingItem
属性的定义。如果您将其定义为id
或NSManagedObject
,则它将不会响应title
选择器并返回nil。它会出错,但你把它转换为Item
,所以编译器认为它将响应Item
对象的所有消息。
除非你知道你会强迫某个物体模仿另一个物体,否则不要使用石膏。否则,您只是创建了隐藏编译器错误的机会。