views:

772

answers:

3

I've got a UITableView with several entries. Upon selecting one, I need it to do a potentially time-consuming network operation. To give the user some feedback, I tried to place a UIActivityIndicatorView in the UITableViewCell. However, the spinner doesn't appear until much later -- after I've done the expensive operation! What am I doing wrong?

- (NSIndexPath *) tableView:(UITableView *) tableView
   willSelectRowAtIndexPath:(NSIndexPath *) indexPath {

  UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
                                       initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];

  [spinner autorelease];
  [spinner startAnimating];
  [[tableView cellForRowAtIndexPath:indexPath] setAccessoryView:activity];

  if ([self lengthyNetworkRequest] == nil) {
    // ...

    return nil;
  }

  return indexPath;
}

As you can see, I have the spinner being set to the accessoryView before the lengthy network operation. But it only appears after the tableView:willSelectRowAtIndexPath: method finishes.

A: 

EDIT: I think you should be using didSelect instead of willSelect.

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath

Try adding [CATransaction flush] right before

if ([self lengthyNetworkRequest] == nil) {
Brandon Schlenker
A: 
- (NSIndexPath *) tableView:(UITableView *) tableView
   willSelectRowAtIndexPath:(NSIndexPath *) indexPath {

  UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
                                       initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];

  [spinner autorelease];
  [spinner startAnimating];
  [[tableView cellForRowAtIndexPath:indexPath] setAccessoryView:activity];

  if ([self lengthyNetworkRequest] == nil) {

    //doing the intensive work after a delay so the UI gets updated first

    [self performSelector:@selector(methodThatTakesALongTime) withObject:nil afterDelay:0.25];

    //you could also choose "performSelectorInBackground"


  }

  return indexPath;
}


- (void)methodthatTakesALongTime{

    //do intensive work here, pass in indexpath if needed to update the spinner again

}
Corey Floyd
A: 

Once you tell the ActivityIndicator to start animating, you have to give your application's run loop a chance to start the animation before starting the long operation. This can be achieved by moving the expensive code into its own method and calling:

[self performSelector:@selector(longOperation) withObject:nil afterDelay:0];
Chris Karcher