- Sample App
- Starting a Core Data Project
- Building Your Managed Object Model
- Setting Up Default Data
- Displaying Your Managed Objects
- Introducing the Fetched Results Controller
- Adding, Editing, and Removing Managed Objects
- Summary
- Exercises
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:
[newMoviesetTitle
:@"New Movie"
]; [newMoviesetYear
:@"2012"
]; [newMoviesetMovieDescription
:@"New movie description."
]; [newMoviesetLent
:@NO
]; [newMoviesetLentOn
:nil
]; [newMovie setTimesWatched:@0
];
Prepare an NSError variable to capture any potential errors, and save the managed object context.
NSError
*mocSaveError =nil
;if
(![mocsave
:&mocSaveError]) {NSLog
(@"Save did not complete successfully. Error: %@"
, [mocSaveErrorlocalizedDescription
]); }
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
(![contextsave
:&error]) {NSLog
(@"Error deleting movie, %@"
, [erroruserInfo
]); }
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
:[saveErrorlocalizedDescription
]delegate
:nil
cancelButtonTitle
:@"Dismiss"
otherButtonTitles
:nil
]; [alertshow
]; }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
];