cs193p – Assignment #6 Part #10

Please note, this blog entry is from a previous course. You might want to check out the current one.

Assignment #6 Task #5

All of your table views everywhere in your application (including the Recents tab) must be driven by Core Data (i.e. not NSUserDefaults nor Flickr dictionaries). You no longer have to support “pulling down to refresh” (though see Extra Credit 1).

To handle the recent entity of the database schema, create another category, containing a single class method:

+ (Recent *)recentPhoto:(Photo *)photo;

When this method gets called, check if the photo has already an entry in the recent entity. If yes, just update the last-viewed time stamp. Otherwise connect the current photo in addition to setting the time stamp. For the last assignment, we had to limit number of recent photos. Therefore, when a new photo is added, check the number of recent photos, and remove the oldest one if there are to many:

+(Recent *)recentPhoto:(Photo *)photo
    Recent *recent = nil;
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Recent"];
    request.predicate = [NSPredicate predicateWithFormat:@"photo = %@", photo];
    NSError *error = nil;
    NSArray *matches = [photo.managedObjectContext executeFetchRequest:request
    if (!matches || ([matches count] > 1)) {
        // handle error
    } else if (![matches count]) {
        recent = [NSEntityDescription insertNewObjectForEntityForName:@"Recent"
        recent.photo = photo;
        recent.lastViewed = [NSDate date];        
        request.predicate = nil;
        request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"lastViewed"
        matches = [photo.managedObjectContext executeFetchRequest:request
        if ([matches count] > RECENT_PHOTOS_MAX_NUMBER) {
            [photo.managedObjectContext deleteObject:[matches lastObject]];
    } else {
        recent = [matches lastObject];
        recent.lastViewed = [NSDate date];
    return recent;

We should update the recent entity only from the region-photos-table-view controller (not the recent-photos-table-view controller), best when we prepare the image view controller. Since this method is currently private to the generic photos-table-view controller we need to make it public:

- (void)prepareViewController:(id)vc
                     forSegue:(NSString *)segueIdentifer
                fromIndexPath:(NSIndexPath *)indexPath;

Now we can overwrite it from within the region-photos-table-view controller:

- (void)prepareViewController:(id)vc
                     forSegue:(NSString *)segueIdentifer
                fromIndexPath:(NSIndexPath *)indexPath
    Photo *photo = [self.fetchedResultsController objectAtIndexPath:indexPath];
    [Recent recentPhoto:photo];
    [super prepareViewController:vc

Finally, adjust the recent-photos-table-view controller to listen for the available database context. Set the fetched-results controller when the context is available:

@property (nonatomic, strong) NSManagedObjectContext *managedObjectContext;
- (void)awakeFromNib
    [super awakeFromNib];
    [[NSNotificationCenter defaultCenter] addObserverForName:PhotoDatabaseAvailabilityNotification
                                                  usingBlock:^(NSNotification *note) {
                                                      self.managedObjectContext = note.userInfo[PhotoDatabaseAvailabilityContext];

- (void)setManagedObjectContext:(NSManagedObjectContext *)managedObjectContext
    _managedObjectContext = managedObjectContext;
    NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Photo"];
    request.predicate = [NSPredicate predicateWithFormat:@"recent != nil"];
    request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"recent.lastViewed"
    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request

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


Leave a Reply

Your email address will not be published.