In this week's lab, you will implement an app that uses Core Data to store information about baseball games. I have provided you with a .plist file containing all 2429 games played during the 2010 Major League Baseball season. This data comes from retrosheet.org. When the app runs, you will display a table with each of the Major League Baseball teams. When a user clicks on that team, you will present another table with a list of all of the games played by that team, sorted by the day that the game was played. The title of each cell will be the two teams that played in the game and the score. The subtitle of each cell will be the date that the game was played.
Like last week's lab, your code:
In this app, you will create a Core Data model with two entities: Team and Game:
After you have created your data model, create the NSManagedObject subclasses called Team and Game. To do this, first select either entity. Then, choose File->New File and from the window that pops up, choose Managed Object Class. Hit Next on the first page. On the second page, select both the Team and the Game entity and hit Finish. Four files, Game.h, Game.m, Team.h, and Team.m will be created. You may want to drag these files to the Classes folder in Xcode.
One of the things we didn't get to talk very much about at the end of yesterday's class was the method +departmentWithName:inManagedObjectContext: located in the Department.m file of the StudentManager-CDTVC+Dept project. What this method, a class method, does is sets up an NSFetchRequest for a Department whose name matches the first parameter, using the NSManagedObjectContext that is the second parameter. If a matching Department is found, that becomes the return value. If a matching Department is not found, a new Department is inserted into the table.
To use this class method, you might say something like this:
Department *csDept = [Department departmentWithName:@"Computer Science" inManagedObjectContext:context];Assuming the context was set up properly, csDept would point to the row in the Department table containing the CS department. If the CS department had not existed in the table before, csDept points to a row that was newly created. If it did exist in the table before, csDept points to the existing row.
In your Team.m file, you will need to create a similar method with the following header (which you'll put in the Team.h file before the first @end:
+ (Team *)teamWithName:(NSString *)aName inManagedObjectContext:(NSManagedObjectContext *)context;This method will allow you to fetch a Team from the database, creating it if it didn't yet exist.
Download the games.plist file. If you double-click on it once it's downloaded, the Property List Editor program will allow you to view the data in the games.plist file. What you should notice is that the top-level item in the property list is an Array (NSArray). Each of the items in the Array is a Dictionary (NSDictionary). Each Dictionary has 5 NSString keys: date associated with an NSDate value, homeTeam and visitingTeam each associated with an NSString value, and homeScore and visitingScore each associated with an NSNumber value. The team names are the three letter abbreviations for each team. (There is no need to convert these to their full names, e.g. MIN=Minnesota Twins, but if you want to do this, you should probably do so in the method described in the next paragraph.)
In your AppDelegate, write a method called -convertToCoreData that will read the games.plist file and save it into your database. These two lines will read in the games.plist file into an NSArray:
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"games" ofType:@"plist"]; NSArray *gamesArray = [NSArray arrayWithContentsOfFile:plistPath];
You should now iterate through the gamesArray. For each game (represented as a dictionary as described above), you will want to:
When you have finished this, you should add [self convertToCoreData]; to your -application:didFinishLaunchingWithOptions: and run your app. If all goes well, you should have now populated your Core Data database with all of the baseball games and you should now comment out that line since you don't want to keep adding the games over and over to your database. You can, of course, check this by using sqlite3 on the command line, or you can write some code similar to what we did in class yesterday by writing and executing an NSFetchRequest and NSLog all of the data, or you can just continue to the next step and hope it all worked...
As I showed in class yesterday, writing a UITableViewController that hooks up to an NSFetchedResults controller is pretty straightforward. The downside is that the UITableViewController that you write will look pretty much like every other UITableViewController you write when using an NSFetchedResults controller. We can pull out nearly all of the common code and use that as the parent class for any new UITableViewController we want to make. Grab the CoreDataTableViewController.zip file. This file was created for the Stanford CS193P class and contains all of the common code. Unzip it and drag the .h and .m files (copying them) to your project.
Now that you have CoreDataTableViewController in your project, we can add a table view controller that will display the list of Teams. Create a New File that is an Objective-C class, subclass of NSObject and call this TeamTableViewController. Inside of TTVC.h, you will need to change the declaration so that your view controller inherits from CoreDataTableViewController instead of NSObject. (Be sure to import CoreDataTableViewController.h.) Inside of TTVC.m, you will need to write only two methods.
- (id)initInManagedObjectContext:(NSManagedObjectContext *)context; - (void)managedObjectSelected:(NSManagedObject *)managedObject;The first method (the init method) you will also want to put in your TTVC.h file.
The init method will have a similar format to the init method in the DeptTableViewController.m file with the following differences:
The second method, -managedObjectSelected:, will look similar to its counterpart in DeptTableViewController.m file with the following differences:
At this point, you can't build and run your app because you need to write the GamesByTeamTableViewController, so let's do it.
Like the TeamTableViewController, create a new Objective-C class, subclass of NSObject. Call this class GamesByTeamTableViewController. Like before, you will want to import the CoreDataTableViewController.h file and have GamesByTeamTableViewController inherit from CoreDataTableViewController instead of NSObject.
Like before, we need to write two methods, though our init method will take the Team we selected as the parameter:
- (id)initWithTeam:(Team *)team; - (void)managedObjectSelected:(NSManagedObject *)managedObject;
Your -initWithTeam: method will look a lot like the -initWithDepartment: method in StudentTableViewController.m except:
- (NSString *)dayPlayed { return [NSDateFormatter localizedStringFromDate:self.gameDate dateStyle:NSDateFormatterMediumStyle timeStyle:NSDateFormatterNoStyle]; }