Please note, this blog entry is from a previous course. You might want to check out the current one.
Photos Table & Image View
Assignment #6 Task #4
When a region is chosen, all the photos in your database that were taken in that region should be displayed (no sections are required). When a photo is then chosen, it should be displayed in the same way photos were displayed in last week’s assignment.
Like in the last part, clear out the generic photo-table-view controller. For now it needs only a single method to setup the table cells using the photo data:
01 02 03 04 05 06 07 08 09 10 11 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:( NSIndexPath *)indexPath { UITableViewCell *cell = [ self .tableView dequeueReusableCellWithIdentifier: @"Photo Cell" ]; Photo *photo = [ self .fetchedResultsController objectAtIndexPath:indexPath]; cell.textLabel.text = photo.title; cell.detailTextLabel.text = photo.subtitle; return cell; } |
Refactor the place-photos-table-view controller to a region-photos-table-view controller. Remove all its properties and methods … Instead, add a single public property to hold the current region:
1 | @property ( nonatomic , strong) Region *region; |
When the region is set, setup the fetched-results controller:
1 2 3 4 5 6 | - ( void )setRegion:(Region *)region { _region = region; self .title = region.name; [ self setupFetchedResultsController]; } |
Get the managed-object context from the current region. Using the region as predicate might produce a problem when we delete the region in the background (remember my region category does that …), thus looking for the regions name generates more stable results:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 | - ( void )setupFetchedResultsController { NSManagedObjectContext *context = self .region.managedObjectContext; if (context) { NSFetchRequest *request = [ NSFetchRequest fetchRequestWithEntityName: @"Photo" ]; request.predicate = [ NSPredicate predicateWithFormat: @"region = %@ OR region.name = %@" , self .region, self .region.name]; request.sortDescriptors = @[[ NSSortDescriptor sortDescriptorWithKey: @"title" ascending: YES selector: @selector (localizedStandardCompare:)]]; self .fetchedResultsController = [[ NSFetchedResultsController alloc] initWithFetchRequest:request managedObjectContext:context sectionNameKeyPath: nil cacheName: nil ]; } else { self .fetchedResultsController = nil ; } } |
… and the regions-table-view controller needs to provide the region to the photos-table-view controller:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 | - ( void )prepareViewController:( id )vc forSegue:( NSString *)segueIdentifer fromIndexPath:( NSIndexPath *)indexPath { Region *region = [ self .fetchedResultsController objectAtIndexPath:indexPath]; if ([vc isKindOfClass:[RegionPhotosTVC class ]]) { RegionPhotosTVC *rpTVC = (RegionPhotosTVC *)vc; rpTVC.region = region; } } - ( void )prepareForSegue:(UIStoryboardSegue *)segue sender:( id )sender { NSIndexPath *indexPath = nil ; if ([sender isKindOfClass:[UITableViewCell class ]]) { indexPath = [ self .tableView indexPathForCell:sender]; } [ self prepareViewController:segue.destinationViewController forSegue:segue.identifier fromIndexPath:indexPath]; } |
… at the current state the code will not run. We changed the generic photos-table-view controller which is also used by the recent-photos-table-view controller … This one is not able to handle Core Data yet … Disable it by commenting out or removing the following line:
1 2 3 4 5 | - ( void )viewWillAppear:( BOOL )animated { [ super viewWillAppear:animated]; // self.photos = [RecentPhotos allPhotos]; } |
To show the photo in the photo view, hand over its URL via a helper method while preparing the segue (for the iPhone) and from the table delegate (for the iPad):
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | - ( void )tableView:(UITableView *)tableView didSelectRowAtIndexPath:( NSIndexPath *)indexPath { id detailvc = [ self .splitViewController.viewControllers lastObject]; if ([detailvc isKindOfClass:[UINavigationController class ]]) { detailvc = [((UINavigationController *)detailvc).viewControllers firstObject]; [ self prepareViewController:detailvc forSegue: nil fromIndexPath:indexPath]; } } - ( void )prepareViewController:( id )vc forSegue:( NSString *)segueIdentifer fromIndexPath:( NSIndexPath *)indexPath { Photo *photo = [ self .fetchedResultsController objectAtIndexPath:indexPath]; if ([vc isKindOfClass:[ImageVC class ]]) { ImageVC *ivc = (ImageVC *)vc; ivc.imageURL = [ NSURL URLWithString:photo.imageURL]; ivc.title = photo.title; } } - ( void )prepareForSegue:(UIStoryboardSegue *)segue sender:( id )sender { NSIndexPath *indexPath = nil ; if ([sender isKindOfClass:[UITableViewCell class ]]) { indexPath = [ self .tableView indexPathForCell:sender]; } [ self prepareViewController:segue.destinationViewController forSegue:segue.identifier fromIndexPath:indexPath]; } |

The complete code for tasks #1 to #7 is available on github.














We can retrieve the managedObjectContext from the core Data instance?
self.region.managedObjectContext is legal?
It is part of the lectures, thus it’s at least legal in the US ;=)
Great!