Today, I came up with a generic UITableViewController that allows single selections.

Part 1: Creating the view controller..

  1. File -> New File -> UIViewController subclass. Check the checkbox UITableViewController subclass.

CheckListTableViewController will be referred to as the controller from here on..

  1. The controller will accept:

a. NSArray *array – which holds the items.
b. NSString *title – title of the selection.

  1. I also added a protocol declaration for the controller when the user presses “Done” on the right portion of the Navbar.

CheckListTableViewController.h

#import
 
@protocol CheckListTableViewControllerDelegate;
 
@interface CheckListTableViewController : UITableViewController {
	//NSString *title;
	NSString *chosenString;
	NSArray *array;
	id delegate;
}
 
//@property(nonatomic, copy) NSString *title;
@property(nonatomic, retain) NSArray *array;
@property(assign) id delegate;
 
- (id)initWithStyle:(UITableViewStyle)style withTitle:(NSString *)t withArray:(NSArray *)a;
 
- (void)doneButtonPressed;
 
- (void)initButton;
 
@end
 
@protocol CheckListTableViewControllerDelegate
 
@optional
 
-(void)checkListTableViewController:(CheckListTableViewController *)controller didChooseString:(NSString *)chosenString;
 
@end
  1. In the cellForRowAtIndexPath, we display the checkmark if the cell’s current String is the same as the chosen String. The chosenString is an ivar which gets assigned during didSelectRowAtIndexPath. Notice that the assignment is performed AFTER the condition of comparing the strings.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
 
    static NSString *CellIdentifier = @"Cell";
 
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
    }
 
    // Set up the cell...
	NSString *currentString = (NSString *)[array objectAtIndex:indexPath.row];
	cell.textLabel.text = currentString;
	cell.textLabel.adjustsFontSizeToFitWidth = YES;
 
	if([currentString localizedCaseInsensitiveCompare:chosenString] == NSOrderedSame ){
		[cell setAccessoryType:UITableViewCellAccessoryCheckmark];
	}
	else{
		[cell setAccessoryType:UITableViewCellAccessoryNone];
	}
 
 
    return cell;
}
 
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // Navigation logic may go here. Create and push another view controller.
	// AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];
	// [self.navigationController pushViewController:anotherViewController];
	// [anotherViewController release];
	NSLog(@"User seleced row %d", indexPath.row);
 
	NSString *currentString = (NSString *)[array objectAtIndex:indexPath.row];
 
	if([currentString localizedCaseInsensitiveCompare:chosenString] == NSOrderedSame ){
		[[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];
	}
	else{
		[[tableView cellForRowAtIndexPath:indexPath] setAccessoryType:UITableViewCellAccessoryNone];
	}
 
	chosenString = currentString;
 
	[tableView reloadData];
}

Part 2: Calling the controller from a client.

  1. Make the client conform to the CheckListTableViewControllerDelegate.
#import
....
#import "DatePickerViewController.h"
#import "CheckListTableViewController.h"
 
@interface JobProfileViewController : UIViewController {
  1. You can even reuse the controller for different lists, say we have two lists:”Purpose” and “Location”
- (IBAction)showPurposePicker{
	NSLog(@"purpose button clicked");
 
	NSArray *array = [[NSArray alloc] initWithObjects:@"Design", @"Testing", nil];
	NSString *title = @"Purpose";
 
	[self displayModalPickerForTitle:title withArray:array];
}
 
- (IBAction)showLocationOfWorkplace{
	NSArray *array = [[NSArray alloc] initWithObjects:@"Both", @"Private", @"Public", nil];
	NSString *title = @"Location";
 
	[self displayModalPickerForTitle:title withArray:array];
}
  1. The controller is added to a Navigation Controller which is presented modally. Courtesy of the help of Erica Sadun from IRC.
- (void)displayModalPickerForTitle:(NSString *)title withArray:(NSArray *)array{
 
	CheckListTableViewController *listController = [[CheckListTableViewController alloc] initWithStyle:UITableViewStylePlain withTitle:title withArray:array];
	listController.delegate = self;
 
	UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:listController];
	[self presentModalViewController:nav animated:YES];
 
	[listController release];
	[nav release];
}
  1. When the user is finished with the control, the client performs its necessary processes and dismisses the modal view.
-(void)checkListTableViewController:(CheckListTableViewController *)controller didChooseString:(NSString *)chosenString{
	NSLog(@"Chosen String: %@", chosenString);
	NSLog(@"Title: %@", controller.title);
 
	if( controller.title == @"Purpose"){
		job.purpose = chosenString;
		[purpose setTitle:job.purpose forState:UIControlStateNormal];
	}
	else if( controller.title == @"Principal Excavation Activity"){
		job.principalExcavationActivity = chosenString;
		[principalExcavationActivity setTitle:job.principalExcavationActivity forState:UIControlStateNormal];
	}
	else if( controller.title == @"Location Of Workplace"){
		job.locationOfWorkplace = chosenString;
		[locationOfWorkplace setTitle:job.locationOfWorkplace forState:UIControlStateNormal];
	}
 
	[self dismissModalViewControllerAnimated:YES];
}