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:

#define RECENT_PHOTOS_MAX_NUMBER 20
+(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
                                                                 error:&error];
    if (!matches || ([matches count] > 1)) {
        // handle error
    } else if (![matches count]) {
        recent = [NSEntityDescription insertNewObjectForEntityForName:@"Recent"
                                               inManagedObjectContext:photo.managedObjectContext];
        recent.photo = photo;
        recent.lastViewed = [NSDate date];        
        request.predicate = nil;
        request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"lastViewed"
                                                                  ascending:NO]];
        matches = [photo.managedObjectContext executeFetchRequest:request
                                                            error:&error];
        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
                        forSegue:segueIdentifer
                   fromIndexPath:indexPath];
}

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
                                                      object:nil
                                                       queue:nil
                                                  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"
                                                              ascending:NO]];
    self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                        managedObjectContext:self.managedObjectContext
                                                                          sectionNameKeyPath:nil
                                                                                   cacheName:nil];
}

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

FacebooktwitterredditpinterestlinkedintumblrmailFacebooktwitterredditpinterestlinkedintumblrmail

Leave a Reply

Your email address will not be published.