【发布时间】:2010-03-10 12:00:43
【问题描述】:
我有一个基于 CoreDataBooks 示例的应用程序,它使用 addingManagedObjectContext 将 Ingredient 添加到 Cocktail 以撤消整个添加。 CocktailsDetailViewController 反过来调用BrandPickerViewController 来(可选地)为给定成分设置品牌名称。 Cocktail、Ingredient 和 Brand 都是 NSManagedObjects。 Cocktail 至少需要设置一个Ingredient (baseLiquor),所以我在创建Cocktail 时创建它。
如果我在CocktailsAddViewController : CocktailsDetailViewController 中添加Cocktail(保存时合并到鸡尾酒托管对象上下文中)而不设置baseLiquor.brand,那么它可以从选择器中设置Brand(也存储在托管的鸡尾酒中上下文)稍后来自CocktailsDetailViewController。
但是,如果我尝试在CocktailsAddViewController 中设置baseLiquor.brand,我会得到:
由于未捕获的异常而终止应用程序 'NSInvalidArgumentException',原因: '非法尝试建立一个 对象之间的关系“品牌” 在不同的情况下'
来自this question我了解到问题是Brand存储在应用程序的managedObjectContext中,而新添加的Ingredient和Cocktail存储在addingManagedObjectContext中,并且通过ObjectID相反会避免崩溃。
我不明白的是如何一般地实现选择器,以便在添加期间可以设置所有成分(baseLiquor、mixer、garnish 等),以及一个-在创建Cocktail 之后,从CocktailsDetailViewController 中删除一个。换句话说,按照 CoreDataBooks 示例,在添加和编辑情况下,ObjectID 将在何时何地从父 MOC 转换为 NSManagedObject? -IPD
更新 - 这是添加方法:
- (IBAction)addCocktail:(id)sender {
CocktailsAddViewController *addViewController = [[CocktailsAddViewController alloc] init];
addViewController.title = @"Add Cocktail";
addViewController.delegate = self;
// Create a new managed object context for the new book -- set its persistent store coordinator to the same as that from the fetched results controller's context.
NSManagedObjectContext *addingContext = [[NSManagedObjectContext alloc] init];
self.addingManagedObjectContext = addingContext;
[addingContext release];
[addingManagedObjectContext setPersistentStoreCoordinator:[[fetchedResultsController managedObjectContext] persistentStoreCoordinator]];
Cocktail *newCocktail = (Cocktail *)[NSEntityDescription insertNewObjectForEntityForName:@"Cocktail" inManagedObjectContext:self.addingManagedObjectContext];
newCocktail.baseLiquor = (Ingredient *)[NSEntityDescription insertNewObjectForEntityForName:@"Ingredient" inManagedObjectContext:self.addingManagedObjectContext];
newCocktail.mixer = (Ingredient *)[NSEntityDescription insertNewObjectForEntityForName:@"Ingredient" inManagedObjectContext:self.addingManagedObjectContext];
newCocktail.volume = [NSNumber numberWithInt:0];
addViewController.cocktail = newCocktail;
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:addViewController];
[self.navigationController presentModalViewController:navController animated:YES];
[addViewController release];
[navController release];
}
这是Brand 选择器中的崩溃位置(此NSFetchedResultsController 由应用委托的托管对象上下文支持:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryCheckmark;
if ([delegate respondsToSelector:@selector(pickerViewController:didFinishWithBrand:forKeyPath:)])
{
[delegate pickerViewController:self
didFinishWithBrand:(Brand *)[fetchedResultsController objectAtIndexPath:indexPath]
forKeyPath:keyPath]; // 'keyPath' is @"baseLiquor.brand" in the crash
}
}
最后是委托实现:
- (void)pickerViewController:(IngredientsPickerViewController *)pickerViewController
didFinishWithBrand:(Brand *)baseEntity
forKeyPath:(NSString *)keyPath
{
// set entity
[cocktail setValue:ingredient forKeyPath:keyPath];
// Save the changes.
NSError *error;
if (![cocktail.managedObjectContext save:&error]) {
// Update to handle the error appropriately.
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
exit(-1); // Fail
}
// dismiss picker
[self.navigationController popViewControllerAnimated:YES]
}
更多
我正在根据 Marcus 的建议取得进展——我将 addingManagedObjectContexts 映射到父 managedObjectContext 并将所有内容包装在 begin/endUndoGrouping 中以处理取消与保存。
但是,要创建的对象在NSFetchedResultsController 中,所以当用户点击“+”按钮添加Cocktail 时,(可能要撤消的)实体会短暂出现在表格中视图作为模态添加视图控制器呈现。 MDN 示例是基于 Mac 的,因此它不涉及此 UI 行为。我该怎么做才能避免这种情况?
【问题讨论】:
-
为什么会有两个托管对象上下文?那很少使用并且是相当高级的东西。我在您对问题空间的描述中看到的任何内容似乎都不需要单独的上下文。
-
我不再使用了,但这就是 Apple CoreDataBooks 示例中用于允许中间撤消的方法——撤消编辑、撤消编辑、撤消(从不)添加。使用单个上下文和撤消分组,我仍在努力恢复中间撤消(撤消整个字段编辑。)
标签: iphone objective-c core-data