Objective-C Programming_ The Big Nerd Ranch Guide - Aaron Hillegass [63]
Implement the callbacks accordingly:
#pragma mark - Table View management
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
// Because this table view only has one section,
// the number of rows in it is equal to the number
// of items in our tasks array
return [tasks count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// To improve performance, we reconfigure cells in memory
// that have scrolled off the screen and hand them back
// with new contents instead of always creating new cells.
// First, we check to see if there's a cell available for reuse.
UITableViewCell *c = [taskTable dequeueReusableCellWithIdentifier:@"Cell"];
if (!c) {
// ...and only allocate a new cell if none are available
c = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:@"Cell"];
}
// Then we (re)configure the cell based on the model object,
// in this case our todoItems array
NSString *item = [tasks objectAtIndex:[indexPath row]];
[[c textLabel] setText:item];
// and hand back to the table view the properly configured cell
return c;
}
To test the application, add some data directly to the array at the top of application:didFinishLaunchingWithOptions:.
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Attempt to load an existing to-do dataset from an array stored to disk.
NSArray *plist = [NSArray arrayWithContentsOfFile:docPath()];
if (plist) {
// If there was a dataset available, copy it into our instance variable.
tasks = [plist mutableCopy];
} else {
// Otherwise, just create an empty one to get us started.
tasks = [[NSMutableArray alloc] init];
}
// Is tasks empty?
if ([tasks count] == 0) {
// Put some strings in it
[tasks addObject:@"Walk the dogs"];
[tasks addObject:@"Feed the hogs"];
[tasks addObject:@"Chop the logs"];
}
// Create and configure the UIWindow instance
CGRect windowFrame = [[UIScreen mainScreen] bounds];
UIWindow *theWindow = [[UIWindow alloc] initWithFrame:windowFrame];
[self setWindow:theWindow];
...
}
Figure 27.8 Complete object diagram for iTahDoodle
Build and run the application. The table view should display your test data. You still can’t add new tasks, though. Once more into the breach!
Adding new tasks
When you created the UIButton instance in application:didFinishLaunchingWithOptions:, you gave it a target/action pair:
[insertButton addTarget:self
action:@selector(addTask:)
forControlEvents:UIControlEventTouchUpInside];
The target is self, and the action is addTask:. So the Insert button sends the BNRAppDelegate the addTask: message. Thus, we need to implement the addTask: method in BNRAppDelegate.m.
- (void)addTask:(id)sender
{
// Get the to-do item
NSString *t = [taskField text];
// Quit here if taskField is empty
if ([t isEqualToString:@""]) {
return;
}
// Add it to our working array
[tasks addObject:t];
// Refresh the table so that the new item shows up
[taskTable reloadData];
// And clear out the text field
[taskField setText:@""];
// Dismiss the keyboard
[taskField resignFirstResponder];
}
What’s this resignFirstResponder business? Here’s the short version:
Some view objects are also controls – views that the user can interact with. Buttons, sliders, and text fields are examples of controls. When there are controls on the screen, one of them can be the first responder. Having first responder status means that the control gets dibs on handling any text input from the keyboard or any shake events (such as “Shake to Undo”).
When the user taps a control that can accept first responder status, that control is sent the becomeFirstResponder message.