Ali Shafai
Ali Shafai

Reputation: 5161

UITableView scrollToRowAtIndexPath

I'm trying to make my table view remember it's last position, so that after the app is run again, it will scroll to that position. to do this, in my viewWillDisappear: method, I get the first visible row number and save it to NSUserDefaults. then in my viewDidAppear I try to scroll to that row by sending scrollToRowAtIndexPath to the table view. However I get a NSRangeException:

*** Terminating app due to uncaught exception 'NSRangeException', reason: '-[UITableView scrollToRowAtIndexPath:atScrollPosition:animated:]: section (0) beyond bounds (0).

any help appreciated. Here is the code:

- (void)viewDidAppear:(BOOL)animated
{
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];

    if ([userDefaults valueForKey:@"content_row"] != nil)
    {
        int rowToHighlight = [[userDefaults valueForKey:@"content_row"] intValue];
        NSIndexPath * ndxPath= [NSIndexPath indexPathForRow:rowToHighlight inSection:0];
        [contentTableView scrollToRowAtIndexPath:ndxPath atScrollPosition:UITableViewScrollPositionTop  animated:YES];
    }
}

-(void) viewWillDisappear:(BOOL)animated
{
    NSIndexPath *selectedRowPath = [[contentTableView indexPathsForVisibleRows] objectAtIndex:0];
    NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
    [userDefaults setInteger:selectedRowPath.row forKey:@"content_row"];
}

Upvotes: 19

Views: 33010

Answers (3)

C. Tewalt
C. Tewalt

Reputation: 2509

I want to elaborate on DyingCactus' answer. I'm a pretty new iOS developer and my situation was a little different, but as he said

"It's possible that the contentTableView has not yet finished loading the data"

While the answer was brief, it got my wheels turning and it was exactly what was happening for me.

My Setup

  • UITableView is on ViewController "A"
  • My app presents a new ViewController "B"
  • On ViewController "B" a button is clicked, then data is added to the data source for the UITableView.
  • From B's button click handler, [tableView reloadData] is called
  • From B's button click handler, [tableView selectRowAtIndexPath:idxPath animated:false scrollPosition:UITableViewScrollPositionTop]; is called
  • ViewController "B" is dismissed and "A" is presented again (showing the updated UITableView)

Solution

  • The first problem I had to fix was to call reloadData on the main thread like so

    [tblView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:false];

  • The last problem was to change waitUntilDone to true (DUH!)

Yeah, so obviously for me, the contentTableView wasn't done loading the data because my reloadData call which is being run on the main thread was not explicitly set to block until the selector was done.

Hope this helps someone.

Upvotes: 0

William Rust
William Rust

Reputation: 640

Reload TableView data before calling scrollToRowAtIndexPath.

[contentTableView reloadData];

Upvotes: 53

user121301
user121301

Reputation:

It's possible that the contentTableView has not yet finished loading the data.

Upvotes: 8

Related Questions