Using UINavigationController with UIViewControllers instances of the same class and without NIB
While trying an experimental UINavigationController based iPhone app, I got an issue where the user went to the previous view.
A simple application uses a UINavigationController to push new instances of UIViewControllers to. These instances are of the same class (in this example, the MyViewController class is a subclass of UIViewController) and are manually created (not using the NIB). Each instance contains a separate UITableView instance as a UIViewController view.
Next tableView: didSelectRowAtIndexPath: method from the MyViewController class. It creates and pushes another instance of MyViewController onto the navigationController when the user selects a table cell:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
MyViewController *nextViewController = [[MyViewController alloc] initWithNibName:nil bundle:nil];
[self.navigationController pushViewController:nextViewController animated:YES];
[nextViewController release];
}
The user can navigate forward through a series of views, each containing a table. The problem occurs when going to the previous screen. The application aborts and xcode starts the debugger.
The error can be prevented by not releasing the MyViewController instance in the tableView: didSelectRowAtIndexPath: method above, or by not calling dealloc on the myTableView instance in the dealloc method of MyViewController. However, this is not a real solution. As far as I know, the UINavigationController "owns" the pushed UIViewController instance, which can then be safely released from the client that allocated it. So what could be wrong with this experimental app? Why does it end when the user navigates back?
Below are a few other methods of the MyViewController class:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
self.title = @"My Table";
myTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
myTableView.delegate = self;
myTableView.dataSource = self;
self.view = myTableView;
}
return self;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"MyTable"];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithFrame:CGRectMake(0,0, 300, 50) reuseIdentifier:@"MyTable"];
[cell autorelease];
}
cell.text = [NSString stringWithFormat:@"Sample: %d", indexPath.row];
return cell;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 3; // always show three sample cells in table
}
- (void)dealloc {
[myTableView dealloc];
[super dealloc];
}
EDIT:
Problem fixed - thanks to Rob Napier for pointing out the problem.
Now the -loadView method sets up the view using the local UITableView instance:
- (void)loadView {
UITableView *myTableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
myTableView.delegate = self;
myTableView.dataSource = self;
self.view = myTableView;
[myTableView release];
}
a source to share