views:

158

answers:

1

I am using tableView:heightForRowAtIndexPath: to set a custom height for each table cell in a UITableView. This is an expensive operation but I have not found a way to speed it up yet (In the future I will be trying some of the methods mentioned by taber).

For now I would just like to display a loading screen of some sort. it does not need to be animated, as long as it is visible while the table view is being loaded. Is this possible?

EDIT: I have tried the loading screen method mentioned in taber's answer, but since it runs in the same thread as the UITableView it does not appear until the table view is finished loading and thus not very useful in this situation :)

+1  A: 

Try #3:

You can add an activity indicator as a new view on top of your table view... something like: http://tapadoo.com/2009/iphone-how-to-do-full-screen-activity-status - then the trick would be figuring out when it's actually finished. I guess in your heightForRowAtIndexPath: method you could keep some kind of row count and check if that count is >= your data model row count. Does that do the trick?

Try #2:

Try to comment out your overridden tableView:heightForRowAtIndexPath: method completely, and instead where you create your cells in cellForRowAtIndexPath: try something like this:



-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

  CGRect contentRectTall = CGRectMake(0.0, 0.0, 302.0, 140.0);
  CGRect contentRectMed = CGRectMake(0.0, 0.0, 302.0, 70.0);
  CGRect contentRectSmall = CGRectMake(0.0, 0.0, 302.0, 42.0);

  ... cell dequeue etc ...

  if ( ...the type of this cell is kRowTypeTall for example... ) {
    cell = [[[UITableViewCell alloc] initWithFrame:contentRectTall reuseIdentifier:CellIdentifier] autorelease];
    ...
  } else if ( ...the cell type is kRowTypeMed ) {
    ...
  } else if ( ...the cell type is kRowTypeSmall ) {
    ...
  }

  ... other cell customization ...

}

Other than that, you might want to look into "lazy loading" where you'd load say the first 50 cells, then add a "load 50 more" type of button at the end.


If you already know your row type (which is contained in some kind of data source) it should be pretty quick to pull out.

Something like...


enum {
  kRowTypeHuge = 0,
  kRowTypeMed,
  kRowTypeSmall
};

-(id)init {
  ...
  NSArray *tableRows = [[NSArray alloc] initWithObjects:
    [NSNumber numberWithUnsignedInt: 0],
    [NSNumber numberWithUnsignedInt: 1],
    [NSNumber numberWithUnsignedInt: 0],
    [NSNumber numberWithUnsignedInt: 0],
    [NSNumber numberWithUnsignedInt: 2],
    nil
  ];
  self.rows = tableRows;
  [tableRows release];
  ...
}

-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
  NSUInteger rowType = [[[self.rows] objectAtIndex: indexPath.row] unsignedIntValue];
  if(rowType == kRowTypeHuge) {
    return 105.0;
  } else if(rowType == kRowTypeMed) {
    return 44.0;
  }
  return 20.0;
}

To be positive that heightForRowAtIndexPath is the issue... does something like this render super fast?


-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
  return 52.0;
}
taber
I did implement a caching mechanism which didnt make it any faster, and the apple documentation on this function mentions that its slow, but your test will make it very clear whether that function is the cause of slowness. I will give it a try tonight and let you know the results. Thank you for your lengthy response :)
Nippysaurus
Cool, please let me know - I'm curious because I haven't really had a problem with this method being slow yet, so I'd like to know too! You must have some pretty crazy rows going on. :)
taber
Not as crazy as you might think ;-) Only about 300 rows, varying between one and four or five rows of text.
Nippysaurus
Does not seem to help. The bottleneck seems to be applying these values to the table view. so the only solution I can think of (to avoid users thinking their phone has crashed) is to display something like a houreglass.
Nippysaurus
Weird, updating my answer with another idea to try... :)
taber
http://developer.apple.com/iphone/library/documentation/uikit/reference/UITableViewDelegate_Protocol/Reference/Reference.html#//apple_ref/occ/intfm/UITableViewDelegate/tableView:heightForRowAtIndexPath:
Nippysaurus
Your method might work, since the cells are a pre-set size even though there are a few different types. Might have to try that method in the future, since it would take a while to implement and debug. For now if you know how to display a loading type screen that would be good :) Else thanks for your idea, I will let you know if it works :)
Nippysaurus
You could add an activity indicator as a new view on top of your table view... something like: http://tapadoo.com/2009/iphone-how-to-do-full-screen-activity-status/ - then the trick would be figuring out when it's finished. i guess in your heightForRowAtIndexPath: method you could keep some kind of row count and check if that count is >= your data model row count. Does that do the trick?
taber
@taber: Put that as an actual answer and I will mark it as the accepted answer. I will consider making the list load faster in the future, but for how the loading screen is great :)
Nippysaurus
thanks! can i set it as Try #3 in this answer to keep everything together? :)
taber