cs193p – Assignment #6 Task #2 Part #1

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

Recreate the user-interface from last week’s assignment but rely entirely on the above-mentioned Core Data database to present it.

Start by copying the content of story board for the iPhone of the previous SPoT project into the current project. Copy the class files for the first table-view controller of the first tab of the previous project together with the files for the network-activity indicator into the current project as well as the core-data-table-view controller from the demo of the lecture.

Define the table view controller as sub class of the ore-data-table-view controller:

@interface FlickrPhotoTagTVC : CoreDataTableViewController


Most of the code previously used to setup the data source for the table view can be removed, because it is now handled by the core-data-table-view-controller methods. Keep only tableView:cellForRowAtIndexPath: and adjust it to use core data:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    ...
    Tag *tag = [self.fetchedResultsController objectAtIndexPath:indexPath];
    cell.textLabel.text = [tag.name capitalizedString];    
    int photoCount = [tag.photos count];    
    ...
}

For the segue instead of handing over an array of photos we provide only the chosen tag:

- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
            ...
            if ([segue.destinationViewController respondsToSelector:@selector(setTag:)]) {
                Tag *tag = [self.fetchedResultsController objectAtIndexPath:indexPath];
                [segue.destinationViewController performSelector:@selector(setTag:)
                                                      withObject:tag];
            }
            ...
}

In viewDidLoad and whenever the table will be “refreshed” by the user loadPhotosFromFlickr is called. Like in the last task the photos are written into core data using the shared document handler which we define as property an instantiate lazily:

- (SharedDocumentHandler *)sh
{
    if (!_sh) {
        _sh = [SharedDocumentHandler sharedDocumentHandler];
    }
    return _sh;
}

- (void)loadPhotosFromFlickr
{
    if (!self.sh.managedObjectContext) [self.sh useDocumentWithOperation:^(BOOL success) {
        [self setupFetchedResultsController];
    }];
    ...
    dispatch_async(queue, ^{
        ...
        [self.sh.managedObjectContext performBlock:^{
            for (NSDictionary *photo in photos) {
                [Photo photoWithFlickrInfo:photo
                    inManagedObjectContext:self.sh.managedObjectContext];
            }
            ...
        }];
    });
}

Note that here we use useDocumentWithOperation: instead of useDocument from the last task because the setup of the fetched-results controller is only possible when the document is ready. Thus we expand the method to perform a block when finished:

- (void)useDocumentWithOperation:(void (^)(BOOL))block
{
    NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
                                                         inDomains:NSUserDomainMask] lastObject];
    ...
    if (![[NSFileManager defaultManager] fileExistsAtPath:[url path]]) {
        [document saveToURL:url
           forSaveOperation:UIDocumentSaveForCreating
          completionHandler:^(BOOL success) {
              ...
              block(success);
          }];
    } else if (document.documentState == UIDocumentStateClosed) {
        [document openWithCompletionHandler:^(BOOL success) {
            ...
            block(success);
        }];
    } else {
        ...
        BOOL success = YES;
        block(success);
    }
}

To setup the fetched-results controller define a fetch request to access the Tag entity and sort it by name:

- (void)setupFetchedResultsController
{
    if (self.sh.managedObjectContext) {
        NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:@"Tag"];
        request.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"name"
                                                                  ascending:YES
                                                                   selector:@selector(localizedCaseInsensitiveCompare:)]];        
        self.fetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:request
                                                                            managedObjectContext:self.sh.managedObjectContext
                                                                              sectionNameKeyPath:nil
                                                                                       cacheName:nil];
    } else {
        self.fetchedResultsController = nil;
    }
}

Finally – it could happen – that the document has been closed while the view was off screen, thus reopen it – if necessary – when it reappears:

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    if (!self.sh.managedObjectContext) [self.sh useDocumentWithOperation:^(BOOL success) {
        [self setupFetchedResultsController];
    }];
}

The complete code is available on github.

FacebooktwitterredditpinterestlinkedintumblrmailFacebooktwitterredditpinterestlinkedintumblrmail

Leave a Reply

Your email address will not be published.