views:

1075

answers:

4

Hi everyone,

Is there some way to find out when a UITableView has finished asking for data from its data source?

None of the viewDidLoad/viewWillAppear/viewDidAppear methods of the associated view controller (UITableViewController) are of use here, as they all fire too early. None of them (entirely understandably) guarantee that queries to the data source have finished for the time being (eg, until the view is scrolled).

One workaround I have found is to call reloadData in viewDidAppear, since, when reloadData returns, the table view is guaranteed to have finished querying the data source as much as it needs to for the time being.

However, this seems rather nasty, as I assume it is causing the data source to be asked for the same information twice (once automatically, and once because of the reloadData call) when it is first loaded.

The reason I want to do this at all is that I want to preserve the scroll position of the UITableView - but right down to the pixel level, not just to the nearest row.

When restoring the scroll position (using scrollRectToVisible:animated:), I need the table view to already have sufficient data in it, or else the scrollRectToVisible:animated: method call does nothing (which is what happens if you place the call on its own in any of viewDidLoad, viewWillAppear or viewDidAppear).

Thanks in advance for your assistance!

A: 

I had something similar I believe. I added a BOOL as instance variable which tells me if the offset has been restored and check that in -viewWillAppear:. When it has not been restored, I restore it in that method and set the BOOL to indicate that I did recover the offset.

It's kind of a hack and it probably can be done better, but this works for me at the moment.

JoostK
Yeah, the problem is that viewWillAppear seems to be too early (at least in my scenario). Trying to restore the offset in viewWillAppear does nothing - unless I add the hack of calling reloadData first.As I understand it, viewWillAppear/viewDidAppear only refer to the table view itself actually appearing - they do not make any claims about whether the table cells in the view have either been enumerated or populated... and this needs to happen before you can recover an offset, as otherwise you would be recovering an offset on an empty view (and I understand why that won't work!).
kennethmac2000
But maybe you meant that you are also forcing the loading of the table cells first by calling reloadData within viewWillAppear?
kennethmac2000
No, I am not forcing a reload. When I had the problem, I tried to restore the offset in `-viewDidLoad` (where it should happen of course) but that did only work when I set the offset animated. By moving the setting of the offset to `-viewWillAppear:` it worked, but I had to maintain a flag to only set it once. I suppose the table view reloads its data once added to a view, so that's already in `-loadView`. Are you sure you have your data available on view load? Or is it being loaded in a separate thread or something?
JoostK
OK, perhaps you can aid my understanding here. This is how I understand the sequence of calls to be when a UITableView is built up.1) viewDidLoad is fired first. This indicates the UITableView is loaded into memory.2) viewWillAppear is next to fire. This indicates that the UITableView will be displayed, but not necessarily that all the visible UITableViewCell objects will be fully instantiated/finished rendering.
kennethmac2000
3) viewDidAppear is then next to fire. This indicates that the UITableView was displayed, but again not necessarily that all the visible UITableViewCell objects were fully instantiated/finished rendering at that point in time.Is this also your understanding?If so, then it seems clear to me that a call to scrollRectToVisible:animated: will only work if the UITableView has obtained enough information about the contained UITableViewCell objects to scroll to the specified position.
kennethmac2000
And all of the above is true, the question then is: what non-hacky options do we have for finding out when the UITableView has obtained sufficient information from its data source to *guarantee* that a scroll request (ie, a scrollRectToVisible:animated: call) will actually work (and not just do nothing)?
kennethmac2000
A: 

Isn't UITableView layoutSubviews called just before the table view displays it content ? I've noticed that it is called once the table view has finished load its data, maybe you should investigate in that direction...

Eric MORAND
A: 

I've been playing with this problem for a couple of days and think that subclassing UITableView's reloadData is the best approach :

  • (void)reloadData {

    NSLog(@"BEGIN reloadData");

    [super reloadData];

    NSLog(@"END reloadData");

}

reloadData doesn't end before the table has finish reload its data. So, when the second NSLog is fired, the table view has actually finish asking for data.

I've subclassed UITableView to send methods to the delegate before and after reloadData. It works like a charm.

Eric MORAND
A: 

finally i have made my code work with this -

[tableView scrollToRowAtIndexPath:scrollToIndex atScrollPosition:UITableViewScrollPositionTop animated:YES];

there are two things which needs to be taken care of -

  1. call it within "- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath"
  2. do not pass this message to UITableView reference which is attached to your controller through IBOutlet - that is do not pass message to self.tableView (this property is declared as IBOutlet UITableView *tableView in my h file) instead pass it to just tableView (passed by the method call)

and yes my UITableView is sub-view to my UIView.

saurabh
and just ensure that this piece is not called more than once. if not it locks the scrolling.
saurabh