NSInvalidArgumentException:非法尝试在不同上下文中的对象之间建立关系

时间:2010-03-10 12:00:43

标签: iphone objective-c core-data

我有一个基于CoreDataBooks示例的应用程序,它使用addingManagedObjectContextIngredient添加Cocktail以撤消整个添加。 CocktailsDetailViewController依次调用BrandPickerViewController来(可选)为给定成分设置品牌名称。 CocktailIngredientBrand都是NSManagedObjectsCocktail要求至少设置一个IngredientbaseLiquor),因此我会在创建Cocktail时创建它。

如果我在Cocktail中添加CocktailsAddViewController : CocktailsDetailViewController(在保存时合并到Cocktail托管对象上下文中)而未设置baseLiquor.brand,那么它可以设置Brand选择器(也存储在鸡尾酒管理的上下文中)稍后从CocktailsDetailViewController

但是,如果我尝试在baseLiquor.brand中设置CocktailsAddViewController,我会得到:

  

由于未捕获的异常而终止应用   'NSInvalidArgumentException',原因:   '非法企图建立一个   对象之间的关系'品牌'   在不同的背景下

来自this question我了解问题是Brand存储在应用的managedObjectContext中,新添加的IngredientCocktail存储在{ {1}},而传递addingManagedObjectContext会避免崩溃。

我没有得到的是如何一般地实施选择器,以便在添加期间可以设置所有成分(ObjectIDbaseLiquormixer等) ,以及garnish创建后的CocktailsDetailViewController逐个引用。换句话说,遵循CoreDataBooks示例,在添加和编辑的情况下,Cocktail在何时何地从父MOC变为ObjectID? -IPD

更新 - 这是添加方法:

NSManagedObject

这里是- (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
    }
}

更多

我正在根据Marcus的建议制作进程 - 我将- (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] } 映射到父managedObjectContext并将所有内容包装在addingManagedObjectContexts中以处理取消与保存。

但是,要创建的对象位于begin/endUndoGrouping中,因此当用户点击“+”按钮添加NSFetchedResultsController时,可能会暂时(可能要撤消)实体当模式添加视图控制器出现时,它出现在表视图中。 MDN示例是基于Mac的,因此它不会触及此UI行为。我该怎么做才能避免这种情况?

2 个答案:

答案 0 :(得分:6)

听起来您正在创建两个不同的核心数据堆栈(NSManagedObjectContextNSManagedObjectModelNSPersistentStoreCoordinator)。您要从示例中执行的操作只是创建指向同一NSManagedObjectContext的两个NSPersistentStoreCoordinator实例。这将解决这个问题。

NSManagedObjectContext视为便笺簿。您可以拥有任意数量的内容,如果在保存之前丢弃它,其中包含的数据就会消失。但他们都保存到同一个地方。

更新

不幸的是,CoreDataBooks是一个非常可怕的例子。但是,对于您的问题,我建议删除创建其他上下文并查看是否发生错误。基于您发布的代码,我假设您直接从Apple的示例中复制的代码,双重上下文,虽然几乎没用,应该可以正常工作。因此我怀疑还有其他的东西在发挥作用。

尝试使用单个上下文,看看问题是否仍然存在。你可能有一些其他有趣但微妙的错误,它会给你这个错误;也许是某个地方的过度释放或沿着那些方向的东西。但第一步是删除双重上下文,看看会发生什么。

更新2

如果即使使用单个MOC也会崩溃,那么您的问题与上下文无关。单个MOC的错误是什么?当我们解决这个问题时,我们将解决您的整个问题。

至于更好的解决方案,请改用NSUndoManager。这就是它的设计目标。 Apple 真的不应该在他们的示例中推荐多个MOC。

我最近在这里回答了关于将NSUndoManager与核心数据一起使用的问题,但您也可以在MDN上查看我的一些文章作为示例。

答案 1 :(得分:0)

是的,在设置对象之间的关系时,您绝对不希望跨越上下文边界;它们都需要在同一个NSManagedObjectContext中。在旧的EOF中,有将错误对象的API用于不同的上下文,但看起来并不像CoreData具有等价物。