MOBILE

iPhone Developer : Integrating Core Data Tables with Live Data Edits, Implementing Undo-Redo Support with Core Data

12/3/2012 6:42:37 PM

Recipe: Integrating Core Data Tables with Live Data Edits

Recipe 1 demonstrates how to move basic table editing tasks into the Core Data world.

  • Adding and deleting items are restricted to the data source— Methods that commit an editing style (i.e., perform deletes) and that add new cells do not directly address the table view. In the original recipe, each method reloaded the table view data after adds and deletes. Recipe 1 saves data to the managed context but does not call reloadData.

  • Data updates trigger table reloads— The actual reloadData call triggers when the fetched results delegate receives a controllerDidChangeContent: callback. This method gets sent when the fetched results object recognizes that the stored data has updated. That happens after data changes have been saved via the managed object context.

  • The table forbids reordering— Recipe 19-3’s tableView:canMoveRowAtIndexPath: method hard codes its result to NO. When working with sorted fetched data sources, users may not reorder that data. This method reflects that reality.

Together, these changes allow your table to work with add and delete edits, as well as content edits. Although content edits are not addressed in this recipe, they involve a similar fetch update approach when users modify attributes used by sort descriptors.

Objects are added by inserting a new entity description. Their attributes are set and the context saved. Objects are deleted from the context, and again the context is saved. These updates trigger the content changed callbacks for the fetched results delegate.

As this recipe shows, the Core Data interaction simplifies the integration between the data model and the user interface. And that’s due in large part to Apple’s thoughtful class designs that handle the managed object responsibilities. Recipe 1 highlights this design, showcasing the code parsimony that results from using Core Data.

Recipe 1. Adapting Table Edits to Core Data
-(void)enterEditMode
{
    // Start editing
    [self.tableView deselectRowAtIndexPath:
        [self.tableView indexPathForSelectedRow] animated:YES];
    [self.tableView setEditing:YES animated:YES];
    [self setBarButtonItems];
}
-(void)leaveEditMode
{
    // Finish editing
    [self.tableView setEditing:NO animated:YES];
    [self setBarButtonItems];
}

- (BOOL)tableView:(UITableView *)tableView
    canMoveRowAtIndexPath:(NSIndexPath *)indexPath
{
    return NO; // no reordering allowed
}

- (void)tableView:(UITableView *)tableView
    commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
    forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Delete request
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
        NSError *error = nil;
        [self.context deleteObject:[fetchedResultsController
            objectAtIndexPath:indexPath]];
        if (![self.context save:&error])
            NSLog(@"Error %@", [error localizedDescription]);
    }

    // Update buttons after delete action
    [self setBarButtonItems];

    // Update sections
    [self performFetch];
}


- (void) add
{
    // Request a string to use as the action item
    NSString *todoAction =
        [ModalAlert ask:@"What Item?" withTextPrompt:@"To Do Item"];
    if (!todoAction || todoAction.length == 0) return;

    // Build a new item and set its action field
    ToDoItem *item = (ToDoItem *)[NSEntityDescription
        insertNewObjectForEntityForName:@"ToDoItem"
        inManagedObjectContext:self.context];
    item.action = todoAction;
    item.sectionName =
        [[todoAction substringToIndex:1] uppercaseString];

    // Save the new item
    NSError *error;
    if (![self.context save:&error])
       NSLog(@"Error %@", [error localizedDescription]);

    // Update buttons after add
    [self setBarButtonItems];

    // Update sections
    [self performFetch];
}

- (void)controllerDidChangeContent:
    (NSFetchedResultsController *)controller
{
    // Update table when the contents have changed
    [self.tableView reloadData];
}

					  

Recipe: Implementing Undo-Redo Support with Core Data

Core Data simplifies table undo-redo support to an astonishing degree. It provides automatic support for these operations with little programming effort. Here are the steps you need to take to add undo-redo to your table based application.

  1. Add an undo manager to the managed object context. After establishing a managed object context (typically in your application delegate), set its undo manager to a newly allocated instance.

    self.context.undoManager =
        [[[NSUndoManager alloc] init] autorelease];
  2. Assign that undo manager in your view controller. Set your view controller’s undo manager to point to the undo manager used by the managed object context.

    self.context = [(TestBedAppDelegate *)
        [[UIApplication sharedApplication] delegate] context];
    self.undoManager = self.context.undoManager;
  3. Optionally, provide shake-to-edit support. If you want your application to respond to device shakes by offering an undo-redo menu, add the following line to your application delegate.

    application.applicationSupportsShakeToEdit = YES;
  4. Ensure that your view controller becomes the first responder when it is onscreen. Provide the following suite of methods. These methods allow the view responder to become first responder whenever it appears. The view controller resigns that first responder status when it moves offscreen.

    - (BOOL)canBecomeFirstResponder {
        return YES;
    }
    
    - (void)viewDidAppear:(BOOL)animated {
        [super viewDidAppear:animated];
        [self becomeFirstResponder];
    }
    
    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        [self resignFirstResponder];
    }

The preceding steps provide all the setup needed to use undo management in your table. Recipe 2 integrates that undo management into the actual delete and add methods for the table. To make this happen, it brackets the core data access with an undo grouping. The beginUndoGrouping and endUndoGrouping calls appear before and after the context updates and saves with changes. An action name describes the operation that just took place.

These three calls (begin, undo, and setting the action name) comprise all the work needed to ensure that Core Data can reverse its operations. For this minimal effort, your application gains a fully realized undo management system, courtesy of Core Data. Be aware that any undo/redo data will not survive quitting your application. This works just as you’d expect with manual undo/redo support.

Recipe 2. Expanding Cell Management for Undo/Redo Support
- (void)tableView:(UITableView *)tableView
    commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
    forRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self.context.undoManager beginUndoGrouping];

    // Delete request
    if (editingStyle == UITableViewCellEditingStyleDelete)
    {
        NSError *error = nil;
        [self.context deleteObject:
            [fetchedResultsController objectAtIndexPath:indexPath]];
        if (![self.context save:&error])
            NSLog(@"Error %@", [error localizedDescription]);
    }

    [self.context.undoManager endUndoGrouping];
    [self.context.undoManager setActionName:@"Delete"];

    // Update buttons after delete action
    [self setBarButtonItems];

    // Update sections
    [self performFetch];
}


- (void) add
{
    // Request a string to use as the action item
    NSString *todoAction = [ModalAlert ask:@"What Item?"
        withTextPrompt:@"To Do Item"];
    if (!todoAction || todoAction.length == 0) return;

    [self.context.undoManager beginUndoGrouping];

    // Build a new item and set its action field
    ToDoItem *item = (ToDoItem *)[NSEntityDescription
        insertNewObjectForEntityForName:@"ToDoItem"
        inManagedObjectContext:self.context];
    item.action = todoAction;

    // Index by the first character of the action
    item.sectionName =
        [[todoAction substringToIndex:1] uppercaseString];

    // Save the new item
    NSError *error;
    if (![self.context save:&error])
        NSLog(@"Error %@", [error localizedDescription]);

    [self.context.undoManager endUndoGrouping];
    [self.context.undoManager setActionName:@"Add"];
    // Update buttons after add
    [self setBarButtonItems];

    // Update sections
    [self performFetch];
}

					  


Other  
 
Top 10
Extending LINQ to Objects : Writing a Single Element Operator (part 2) - Building the RandomElement Operator
Extending LINQ to Objects : Writing a Single Element Operator (part 1) - Building Our Own Last Operator
3 Tips for Maintaining Your Cell Phone Battery (part 2) - Discharge Smart, Use Smart
3 Tips for Maintaining Your Cell Phone Battery (part 1) - Charge Smart
OPEL MERIVA : Making a grand entrance
FORD MONDEO 2.0 ECOBOOST : Modern Mondeo
BMW 650i COUPE : Sexy retooling of BMW's 6-series
BMW 120d; M135i - Finely tuned
PHP Tutorials : Storing Images in MySQL with PHP (part 2) - Creating the HTML, Inserting the Image into MySQL
PHP Tutorials : Storing Images in MySQL with PHP (part 1) - Why store binary files in MySQL using PHP?
REVIEW
- First look: Apple Watch

- 3 Tips for Maintaining Your Cell Phone Battery (part 1)

- 3 Tips for Maintaining Your Cell Phone Battery (part 2)
VIDEO TUTORIAL
- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 1)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 2)

- How to create your first Swimlane Diagram or Cross-Functional Flowchart Diagram by using Microsoft Visio 2010 (Part 3)
Popular Tags
Microsoft Access Microsoft Excel Microsoft OneNote Microsoft PowerPoint Microsoft Project Microsoft Visio Microsoft Word Active Directory Biztalk Exchange Server Microsoft LynC Server Microsoft Dynamic Sharepoint Sql Server Windows Server 2008 Windows Server 2012 Windows 7 Windows 8 Adobe Indesign Adobe Flash Professional Dreamweaver Adobe Illustrator Adobe After Effects Adobe Photoshop Adobe Fireworks Adobe Flash Catalyst Corel Painter X CorelDRAW X5 CorelDraw 10 QuarkXPress 8 windows Phone 7 windows Phone 8 BlackBerry Android Ipad Iphone iOS