Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why does this code use presentModalViewController? (not pushViewController)

Anyone understand why in the CoreDataBooks example code that:

(a) method for controller swapping difference

Whilst the click an item and go to detailed view uses what seems to be the standard UINavigationController concept of "pushViewController", that when when you click on the "Add" a new record button it launches the new view to add the record via "presentModalViewController" approach? That is, couldn't the approach have been the same in both cases, just using a pushViewController approach?

Are there actually any advantages to using each approach for where it's been used? I can't quite see. I'd guess there must have been something for Apple to choose these different approaches for different scenarios. For example:

  1. any differences to the user (i.e. UI differences or functional differences) that they would see?

  2. any differences for the developer (or advantages/disadvantages)

For example, if you were to consider using pushViewController approach instead of the presentModalViewController approach for the for the "Add" scenario...

(b) data sharing approach difference

the approach to how they share the common data object seems to be different - so again just wondering why the approaches weren't the same? (i.e. in both cases the main controller is passing off to another view temporarily and there is some shared data between them - i.e. that the child view needs to pass back to the parent)

Code Extract for Convenience

That is for "Edit":

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Create and push a detail view controller.
    DetailViewController *detailViewController = [[DetailViewController alloc] initWithStyle:UITableViewStyleGrouped];
    Book *selectedBook = (Book *)[[self fetchedResultsController] objectAtIndexPath:indexPath];

    // Pass the selected book to the new view controller.
    detailViewController.book = selectedBook;
    [self.navigationController pushViewController:detailViewController animated:YES];
    [detailViewController release];
}

But for "Add"

- (IBAction)addBook {
    AddViewController *addViewController = [[AddViewController alloc] initWithStyle:UITableViewStyleGrouped];
     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]];
     addViewController.book = (Book *)[NSEntityDescription insertNewObjectForEntityForName:@"Book" inManagedObjectContext:addingContext];
     UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:addViewController];
        [self.navigationController presentModalViewController:navController animated:YES];

     [addViewController release];
     [navController release];

}

thanks

like image 210
Greg Avatar asked Dec 28 '22 01:12

Greg


2 Answers

You use modal view controllers to focus the user's attention on a Task. When you push, the user is in some kind of navigation flow, but still has the total application at their fingertips. They might decide to go forward or backward, switch to a different tab in the middle, whatever. When they get a modal view controller, they can't do any of that until the task is completed or canceled out of (the modal view is dismissed)

like image 168
DVG Avatar answered Apr 29 '23 03:04

DVG


[Warning: this answer applies more to the updated code of the CoreDataBooks, which has changed to use the new-in-iOS5 setParentContext method of NSManagedObjectContext instead of messing with the persistentStoreCoordinator[

Your 2nd question about data sharing is also answered by the modal Add vs modeless Edit approach. Run the app in the simulator and notice that:

  1. if you click on Add your next view has both Save and Cancel buttons

  2. if you click on Edit your next view has only a Done button.

(Now, in this particular project, you have to edit each field at a time and the field editing is done in yet another view, and that one has a Cancel button, but ignore that for now, because

a. this only applies to the field. E.g. If you edit a Title and hit Save, you're back at the Edit view with the Done button, now there's no cancel to undo that change, you can only hit Done. As far as this view is concern, you've edited the Book modeLESSly

b. What a lame UI! Come on Apple, make the CoreDataBooks into a decent, albeit simple app that follows your own conventions. At least put the editing in the cells.)

Where were we? Oh yeah, "Edit"-ing an existing Book is modeLESS, so it passes the original Book in the same MOC (NSManagedObjectContext) and you can't cancel your edits to it in the Edit view. "Add"-ing a Book, on the other hand is MODAL: It creates a new Book for to be edited in the detail view, and wants to discard it if the user hits cancel. To achieve this it has to use a second MOC, which is a child of the first. If the user Cancels, it simply ignores the new child MOC, effectively discarding the new Book; if the user Saves, it saves the child MOC, which pushes the new Book and its properties up into the parent MOC, then saves the parent MOC.

This child-MOC approach, btw, is detailed in the WWDC 2011 presentation 303 "What's new in Core Data on iOS". There are other approaches discussed elsewhere in SO, including

  • Creating a new managed object with a nil MOC, and only inserting it in the parent MOC when the user hits save

  • Not using a managed object but a different data structure for the temporary object (the new Book that we're not sure we want to save yet), such as an NSDictionary, or just a set of different variables

  • and more... ?

I kind of prefer the parent-child approach because Apple favours it and because it makes use of the data model objects instead of creating parallel data structures for temporary objects. The nil-context approach also has that benefit, and the added benefit of (apparently) better performance and simplicity (read my lips: no new MOCs). But I'm not convinced that managed objects without managed object contexts are kosher.

By the way, CoreDataBooks doesn't exactly follow the convention laid down in the aforementioned presentation, because it doesn't save the parent context in a performBlock block.

Also I'm not sure why it sets the new managed context as a property on the AddViewController and doesnt use it.

like image 23
Rhubarb Avatar answered Apr 29 '23 02:04

Rhubarb