Please note, this blog entry is from a previous course. You might want to check out the current one.
The sixth assignment continues the application from the last assignments which create a Flickr photo browser. This assignment will add features emphasizing the use of Core Data.
This application lets the user assemble a Virtual Vacation of places in the world to visit. Users will use the photo-choosing capabilities of your Fast Map Places application to choose photos in the places they want to go. In this application you will have two major tasks: allowing the user to choose where they want to go and allowing the user to “go on vacation” in their Virtual Vacation spots. You will accomplish the former by adding a “Visit/Unvisit” button to the scenes in your Fast Map Places where a photo is displayed. You will accomplish the latter by adding a new tab to your Tab Bar Controller which lets the user peruse their Virtual Vacation either by place or by searching for tags that were found in the Flickr dictionaries for the photos they chose to visit.
1. Add a new tab to your application that displays a new table view controller showing a list of all the “Virtual Vacations” found in the user’s Documents directory in their sandbox. A Virtual Vacation file is created by saving a UIManagedDocument (more on this below). Each vacation must have it’s own separate file in the Documents directory.
Add to both storyboards an additional navigation view controller and an table view controller, create a sub class for the table view, set it up in the story boards and change the cell reuse identifier to “Vacation Cell”. Finally add a relationship segue from the tab view controller to the new navigation view controller (There should already be a segue from the new navigation view controller to the new table view controller).
Because the new table view controller should show the available vacations the model for this class is an array holding their names. It is populated using lazy instantiation. The number of rows equals the number of vacations, and a cell should just show the name of the vacation:
// VacationsTableViewController.h @property (nonatomic, strong) NSArray *vacations; // VacationsTableViewController.m @synthesize vacations = _vacations; - (NSArray *)vacations { if (!_vacations) _vacations = [VacationHelper getVacations]; return _vacations; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return [self.vacations count]; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"Vacation Cell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (!cell) cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier]; cell.textLabel.text = [self.vacations objectAtIndex:indexPath.row]; return cell; }
… and to be able to use auto rotation:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return YES; }
The array of vacations is derived using a helper class VacationsHelper more specifically its class method getVacations. First it creates a file manager and sets the base folder, by searching the documents directory. To get a clean directory structure and do not have problems should something else then a vacation be stored in the documents directory, we add an addition subfolder, e.g. “vacations”. If this directory does not exist, it will be created. Finally we fetch the contents of this folder and to simplify the further code we fetch the file names as additional property and skip hidden files. Looping over the resulting file list, we generate the vacations array. Should there be no vacation yet, we return the default vacation name.
+ (NSArray *)getVacations { NSFileManager *fm = [[NSFileManager alloc] init]; NSURL *dir = [[[fm URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject] URLByAppendingPathComponent:DEFAULT_DATABASE_FOLDER isDirectory:YES]; BOOL isDir = NO; NSError *error; if (![fm fileExistsAtPath:[dir path] isDirectory:&isDir] || !isDir) [fm createDirectoryAtURL:dir withIntermediateDirectories:YES attributes:nil error:&error]; if (error) return nil; NSArray *files = [fm contentsOfDirectoryAtURL:dir includingPropertiesForKeys:[NSArray arrayWithObject:NSURLNameKey] options:NSDirectoryEnumerationSkipsHiddenFiles error:&error]; if (error) return nil; NSString *name; NSMutableArray *vacations = [NSMutableArray arrayWithCapacity:[files count]]; for (NSURL *url in files) { [url getResourceValue:&name forKey:NSURLNameKey error:&error]; if (error) continue; [vacations addObject:name]; } if ([vacations count]) return vacations; return [NSArray arrayWithObject:DEFAULT_VACATION_NAME];; }
The complete code for this task is available at github.