Home > Articles > Programming > General Programming/Other Languages

  • Print
  • + Share This
This chapter is from the book

Adding, Editing, and Removing Managed Objects

Although it is useful to be able to fetch and display data, apps often need to add new data, edit existing data, and remove unneeded data at the user’s request.

Inserting a New Managed Object

In the sample app, view the Movies tab. To insert a new movie, the user can tap the Add button in the navigation bar. The Add button is wired to perform a segue to the ICFMovieEditViewController. In the segue logic, a new movie managed object is inserted into Core Data, and the new movie’s object ID is passed to the edit movie view controller. This approach is used in the sample app to prevent having logic in the edit view controller to handle both creating new managed objects and editing existing managed objects; however, it would be perfectly acceptable to create the new movie managed object in the edit view controller if that makes more sense in a different app.

To create a new instance of a movie managed object, a reference to the managed object context is needed.

NSManagedObjectContext *moc =
 [kAppDelegate managedObjectContext];

To insert data, Core Data needs to know what entity the new data is for. Core Data has a class called NSEntityDescription that provides information about entities. Create a new instance using NSEntityDescription’s class method:

ICFMovie *newMovie = [NSEntityDescription
 insertNewObjectForEntityForName:@"Movie"
     inManagedObjectContext:moc];

Populate the new movie managed object’s attributes with data:

[newMovie setTitle:@"New Movie"];
[newMovie setYear:@"2012"];
[newMovie setMovieDescription:@"New movie description."];
[newMovie setLent:@NO];
[newMovie setLentOn:nil];
[newMovie setTimesWatched:@0];

Prepare an NSError variable to capture any potential errors, and save the managed object context.

NSError *mocSaveError = nil;

if (![moc save:&mocSaveError])
{
  NSLog(@"Save did not complete successfully. Error: %@",
     [mocSaveError localizedDescription]);
}

After the managed object context has been successfully saved, the fetched results controller will be notified if the save affects the results of the controller’s fetch, and the delegate methods described earlier in the chapter will be called.

Removing a Managed Object

On the Movies tab in the sample app, the user can swipe on the right side of a table cell, or can tap the Edit button to reveal the delete controls for each table cell. When Delete is tapped on a cell, the table view delegate method tableView:commitEditingStyle:forRowAtIndexPath: is called. The method checks whether the editing style is delete. If so, the method gets a reference to the managed object context from the fetched results controller. The fetched results controller keeps a reference to the managed object context it was initialized with, which is needed to delete the object.

NSManagedObjectContext *context =
 [self.fetchedResultsController managedObjectContext];

The method determines which managed object should be deleted, by asking the fetched results controller for the managed object at the specified index path.

NSManagedObject *objectToBeDeleted =
 [self.fetchedResultsController objectAtIndexPath:indexPath];

To delete the managed object, the method tells the managed object context to delete it.

[context deleteObject:objectToBeDeleted];

The deletion is not permanent until the managed object context is saved. After it is saved, the delegate methods described earlier in the chapter will be called and the table will be updated.

NSError *error = nil;
if (![context save:&error])
{
  NSLog(@"Error deleting movie, %@", [error userInfo]);
}

Editing an Existing Managed Object

On the Movies tab in the sample app, the user can tap a movie to see more detail about it. To change any of the information about the movie, tap the Edit button in the navigation bar, which will present an instance of ICFMovieEditViewController. When the view is loaded, it will load an instance of ICFMovie using the objectID passed in from the display view or list view, will save that instance into the property editMovie, and will configure the view using information from the movie managed object.

If the user decides to edit the year of the movie, for example, another view controller will be presented with a UIPickerView for the user to select a new year. The ICFMovieEditViewController is set up as a delegate for the year chooser, so when the user has selected a new year and taps Save, the delegate method chooserSelectedYear: is called. In that method, the editMovie is updated with the new date and the display is updated.

- (void)chooserSelectedYear:(NSString *)year
{
    [self.editMovie setYear:year];
    [self.movieYearLabel setText:year];
}

Note that the managed object context was not saved after editMovie was updated. The managed object editMovie can keep updates temporarily until the user makes a decision about whether to make the changes permanent, indicated by tapping the Save or Cancel button.

Saving and Rolling Back Your Changes

If the user taps the Save button, he has indicated his intention to keep the changes made to the editMovie. In the saveButtonTouched: method, the fields not updated with delegate methods are saved to the editMovie property:

NSString *movieTitle = [self.movieTitle text];
[self.editMovie setTitle:movieTitle];

NSString *movieDesc = [self.movieDescription text];
[self.editMovie setMovieDescription:movieDesc];

BOOL sharedBool = [self.sharedSwitch isOn];
NSNumber *shared = [NSNumber numberWithBool:sharedBool];
[self.editMovie setLent:shared];

Then the managed object context is saved, making the changes permanent.

NSError *saveError = nil;
[kAppDelegate.managedObjectContext save:&saveError];
if (saveError)
{

  UIAlertView *alert =
   [[UIAlertView alloc]
    initWithTitle:@"Error saving movie"
         message:[saveError localizedDescription]
        delegate:nil
    cancelButtonTitle:@"Dismiss"
    otherButtonTitles:nil];

  [alert show];
}
else
{
  NSLog(@"Changes to movie saved.");
}

If the user decides that the changes should be thrown away and not be made permanent, the user will tap the Cancel button, which calls the cancelButtonTouched: method. That method will first check whether the managed object context has any unsaved changes. If so, the method will instruct the managed object context to roll back or throw away the unsaved changes. After that is completed, the managed object context will be back to the state it was in before any of the changes were made. Rather than the user interface being updated to reflect throwing away the changes, the view is dismissed.

if ([kAppDelegate.managedObjectContext hasChanges])
{
  [kAppDelegate.managedObjectContext rollback];
  NSLog(@"Rolled back changes.");
}

[self.navigationController.presentingViewController
 dismissModalViewControllerAnimated:YES];
  • + Share This
  • 🔖 Save To Your Account