views:

231

answers:

2

I'm facing what appears to be a UIKit bug, and it takes the combination of two less commonly used features to reproduce it, so please bear with me here.

I have quite the common view hierarchy:

UITabBarController -> UINavigationController -> UITableViewController

and the table view controller pushes another table view controller onto the navigation controller's stack when a row is selected. There's absolutely nothing special or fancy in the code here.

However, the second UITableViewController, the "detail view controller" if you will, does two things:

  1. It sets hidesBottomBarWhenPushed to YES in its init method, so the tab bar is hidden when this controller is pushed:

    - (id)initWithStyle:(UITableViewStyle)style {
        if(self = [super initWithStyle:style]) {
            self.hidesBottomBarWhenPushed = YES;
        }
        return self;
     }
    
  2. It calls setToolbarHidden:NO animated:YES and setToolbarHidden:YES animated:YES on self.navigationController in viewWillAppear: and viewWillDisappear: respectively, causing the UIToolbar provided by UINavigationController to be displayed and hidden with animations:

    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        [self.navigationController setToolbarHidden:NO animated:YES];
    }
    
    
    - (void)viewWillDisappear:(BOOL)animated {
        [super viewWillDisappear:animated];
        [self.navigationController setToolbarHidden:YES animated:YES];
    }
    

Now, if the second UITableViewController was pushed by selecting the row at the bottom of the screen (it doesn't have to be the last row) in the first controller, this row does not automatically get deselected when the user immediately or eventually returns to the first controller.

Further, the row cannot be deselected by calling deselectRowAtIndexPath:animated: on self.tableView in viewWillAppear: or viewDidAppear: in the first controller.

I'm guessing this is a bug in UITableViewController's drawing code which of course only draws visible rows, but unfortunately fails to determine correctly if the bottommost row will be visible in this case.

I failed to find anything on this on Google or OpenRadar, and was wondering if anyone else on SO had this problem or knew a solution/workaround.

+1  A: 

I had this same exact problem, (though I am not using a toolbar). My solution was to deselect the row in didSelectRowAtIndexPath after pushing my second view controller.

- (void)tableView:(UITableView *)aTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    RunViewController *runViewController = [[RunViewController alloc] initWithNibName:@"RunViewController" bundle:nil];
    runViewController.managedObjectContext = self.managedObjectContext;
    runViewController.hidesBottomBarWhenPushed = YES;
    [self.navigationController pushViewController:runViewController animated:YES];
    [runViewController release];

     //deslect "stuck" row
    [aTableView deselectRowAtIndexPath:indexPath animated:YES]; 
}
Eric Schweichler
Of course this is different from the default and expected behavior.
Can Berk Güder
Well, when it started happening, I certainly thought that it was unexpected, but the solution above worked for me so I didn't really pursue it any further.
Eric Schweichler
A: 

If I remember well I think I had same/similar problem once, but my solution was rather rough:

- (UITableViewCell*)tableView:(UITableView*)tableView 
        cellForRowAtIndexPath:(NSIndexPath*)indexPath {
  // ...
  cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
Daniel Bauke