从segue添加Core Data对象

时间:2013-07-16 05:38:28

标签: xcode core-data segue nsmanagedobject

在熟悉核心数据时,我发现自己对于在尝试添加数据时通过各种视图控制器(VC)的问题感到困惑。

例如,在Apple提供的CoreDataRecipes项目中(http://developer.apple.com/library/ios/#samplecode/iPhoneCoreDataRecipes/Introduction/Intro.html),他们使用以下方法

当用户想要将配方添加到主表视图中显示的配方列表中,并点击添加按钮时,主表视图控制器(称为RecipeListTableViewController)创建一个新的管理对象(配方),如下所示: / p>

- (void)add:(id)sender {
 // To add a new recipe, create a RecipeAddViewController.  Present it as a modal view so that the user's focus is on the task of adding the recipe; wrap the controller in a navigation controller to provide a navigation bar for the Done and Save buttons (added by the RecipeAddViewController in its viewDidLoad method).
RecipeAddViewController *addController = [[RecipeAddViewController alloc] initWithNibName:@"RecipeAddView" bundle:nil];
addController.delegate = self;

Recipe *newRecipe = [NSEntityDescription insertNewObjectForEntityForName:@"Recipe" inManagedObjectContext:self.managedObjectContext];
addController.recipe = newRecipe;

UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:addController];
[self presentModalViewController:navigationController animated:YES];

[navigationController release];
[addController release];
}

将这个新创建的对象(一个Recipe)传递给RecipeAddViewController。 RecipeAddViewController有两种方法,save和cancel,如下所示:

- (void)save {

recipe.name = nameTextField.text;

NSError *error = nil;
if (![recipe.managedObjectContext save:&error]) {
    /*
     Replace this implementation with code to handle the error appropriately.

     abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
     */
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}       

[self.delegate recipeAddViewController:self didAddRecipe:recipe];

}

- (void)cancel {

[recipe.managedObjectContext deleteObject:recipe];

NSError *error = nil;
if (![recipe.managedObjectContext save:&error]) {
    /*
     Replace this implementation with code to handle the error appropriately.

     abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development. If it is not possible to recover from the error, display an alert panel that instructs the user to quit the application by pressing the Home button.
     */
    NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
    abort();
}       

[self.delegate recipeAddViewController:self didAddRecipe:nil];

}

我对这种设计方法感到困惑。在我们知道用户是否想要实际输入新的配方名称并保存新对象之前,为什么RecipeListViewController应该创建对象?为什么不将managedObjectContext传递给addRecipeController,并等到用户点击save来创建对象并用数据填充其字段?如果没有新的配方可以添加,这可以避免必须删除新对象。或者为什么不在RecipeListViewController和RecipeAddController之间来回传递食谱名称(字符串)?

我在问,因为我很难理解何时在segue之间传递字符串,何时传递对象以及何时传递managedObjectContexts ......

任何非常感谢的指导,包括与讨论设计理念有关的任何链接。

1 个答案:

答案 0 :(得分:1)

您的问题是NSManagedObject无法在没有上下文的情况下生存。因此,如果您不向上下文添加配方,则必须在“常规”实例变量中保存该配方的所有属性。当用户点击保存时,您可以从这些实例变量中创建配方。

这对于AddViewController来说不是一个大问题,但是你想用什么viewController来编辑食谱?您可以重用AddViewController。但是如果将所有数据保存为实例变量,它会变得有点难看,因为首先必须从配方中获取所有数据,将其保存到实例变量,完成后你必须反过来。

这就是为什么我通常使用不同的方法。我使用编辑上下文进行编辑(或添加,基本上只是编辑)。

- (void)presentRecipeEditorForRecipe:(MBRecipe *)recipe {
    NSManagedObjectContext *editingContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    editingContext.parentContext = self.managedObjectContext;
    MBRecipe *recipeForEditing;
    if (recipe) {
         // get same recipe inside of the editing context. 
        recipeForEditing = (MBRecipe *)[editingContext objectWithID:[recipe objectID]];
        NSParameterAssert(recipeForEditing);
    }    
    else {
        // no recipe for editing. create new one
        recipeForEditing = [MBRecipe insertInManagedObjectContext:editingContext];
    }

    // present editing view controller and set recipeForEditing and delegate
}

非常简单的代码。它创建一个用于编辑的新子上下文。并从该上下文中获取编辑的配方。

您必须在EditViewController中保存上下文!只需设置Recipe的所有所需属性,但保留上下文。

用户点击“取消”或“完成”后,将调用此委托方法。哪个保存editContext和我们的上下文或什么都不做。

- (void)recipeEditViewController:(MBRecipeEditViewController *)editViewController didFinishWithSave:(BOOL)didSave {
    NSManagedObjectContext *editingContext = editViewController.managedObjectContext;
    if (didSave) {
        NSError *error;
        // save editingContext. this will put the changes into self.managedObjectContext
        if (![editingContext save:&error]) {
            NSLog(@"Couldn't save editing context %@", error);
            abort();
        }

        // save again to save changes to disk
        if (![self.managedObjectContext save:&error]) {
            NSLog(@"Couldn't save parent context %@", error);
            abort();
        }
    }
    else {
        // do nothing. the changes will disappear when the editingContext gets deallocated
    }
    [self dismissViewControllerAnimated:YES completion:nil];
    // reload your UI in `viewWillAppear:`
}