У меня есть приложение, основанное на примере CoreDataBooks, которое использует addingManagedObjectContext
для добавления Ingredient
к Cocktail
для отмены всего добавления. CocktailsDetailViewController
, в свою очередь, вызывает BrandPickerViewController
, чтобы (необязательно) установить название бренда для данного ингредиента. Cocktail
, Ingredient
и Brand
- все NSManagedObjects
. Cocktail
требует, чтобы был установлен хотя бы один Ingredient
(baseLiquor
), поэтому я создаю его при создании Cocktail
.
Если я добавлю Cocktail
в CocktailsAddViewController : CocktailsDetailViewController
(слияние с контекстом управляемого объекта Cocktail при сохранении) без установки baseLiquor.brand
, то получится установить Brand
из средства выбора (также сохраненного в управляемых коктейлях). контекст) позже от CocktailsDetailViewController
.
Однако, если я попытаюсь установить baseLiquor.brand
в CocktailsAddViewController
, я получу:
Завершение приложения из-за необработанного исключения
NSInvalidArgumentException, причина:
«Незаконная попытка установить
отношения «бренд» между объектами
в разных контекстах '
С этот вопрос Я понимаю, что проблема в том, что Brand
хранится в managedObjectContext
приложения, а недавно добавленные Ingredient
и Cocktail
хранятся в addingManagedObjectContext
, и что прохождение ObjectID
вместо этого позволит избежать сбоя.
Чего я не понимаю, так это как реализовать средство выбора, чтобы все ингредиенты (baseLiquor
, mixer
, garnish
и т. Д.) Могли быть установлены во время добавления, а также одно- по одному из CocktailsDetailViewController
после создания Cocktail
. Другими словами, следуя примеру CoreDataBooks, где и когда ObjectID
будет превращено в NSManagedObject
из родительского MOC в случаях добавления и редактирования? -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]
}
ДАЖЕ БОЛЬШЕ
Я делаю прогы на основе предложений Маркуса - я сопоставил addingManagedObjectContexts
с родительским managedObjectContext и завернул все в begin/endUndoGrouping
для обработки отмены и сохранения.
Однако создаваемый объект находится в NSFetchedResultsController
, поэтому, когда пользователь нажимает кнопку «+», чтобы добавить Cocktail
, сущность (возможно, подлежащая отмене) кратко появляется в таблице. view в качестве модального контроллера. Пример MDN основан на Mac, поэтому он не затрагивает это поведение пользовательского интерфейса. Что я могу сделать, чтобы избежать этого?