views:

31

answers:

2

Hi all,

I've been working on a simple iPhone app for a couple of days now, and haven't been able to wrap my head around quite a bit of the interface. Specifically, I've got a main menu view with an ImageView and a couple of buttons that will eventually swap out to other views.

In addition to the main menu, I've got a UIViewController subclass called Browse_Phone (it's a Universal app), and it contains a UITableView called tableView. It'll eventually be hooked up to a database, but for now, the contents of the table are hard-coded. The following is the table delegate code in Browse_Phone.m (most of this code is borrowed from online examples):

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return 5;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
    }

    NSString *szCell = [[NSString alloc] initWithFormat: @"Row %i", indexPath.row ];

    cell.textLabel.text = szCell;

    [szCell release];

    // Set up the cell
    return cell;
}

// The designated initializer.  Override if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])
    {
        self.title = @"Browse";
        tableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
        tableView.delegate = self;
        tableView.dataSource = self;
        self.view = tableView;
    }
    return self;
}

Finally, in the main window, there's a button to swap out the main menu view with a navigation controller that uses a Browse_Phone controller as its RootViewController (note that [sender superview] is the main menu view):

- (IBAction)loadBrowse:(id)sender
{
    Browse_Phone *browsePhone = [[[Browse_Phone alloc] initWithNibName:nil bundle:nil] autorelease];
    if(browsePhone.view)
    {
        UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:browsePhone] autorelease];
        CGContextRef context = UIGraphicsGetCurrentContext();
        [UIView beginAnimations:nil context:context];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
        [UIView setAnimationDuration:0.5];
        [UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:window cache:YES];

        [[sender superview] removeFromSuperview];
        [window addSubview:navController.view];

        [UIView commitAnimations];
    }
}

When I press the button, the view swap seems to work. The flip occurs as expected, and the navigation control is loaded, but the table is nowhere to be found. I know the Browse_Phone controller is being instantiated, because the navigation bar's title reflects that of the table. When I used this code in a simple app that just loaded the controllers in the app delegate's didFinishLaunchingWithOptions, it worked just fine. Of course, I know the problem is going to be something simple that I've missed.

Thanks in Advance,

Ryan

A: 

It's your initWithNibName:bundle: method.

loadView gets called after initWithNibName:bundle: and overrides your view. You should load your view in loadView, or better yet, subclass UITableViewController (instead of UIViewController) and let it do everything for you.

Can Berk Güder
And I'll be doing some fancy skinning of the table once it's all up and running, which I've read is impossible with UITableViewController; that's why I'm avoiding it.
Ryan
I moved the view loading code into loadView, and it made no difference.
Ryan
A: 

All right, I think I understand the problem; it looks like somewhere during the creation and initialization of the view controllers, they're being set to autorelease, so when I explicitly set them to autorelease, they wind up being released one too many times. So before the table gets a chance to render, the controller's retain count drops to 0 and it gets dumped. Removing the autorelease from each controller's initialization in loadBrowse fixes the problem. I can't say I understand why the app doesn't just crash outright, but the problem appears to be solved for the time being.

Ryan