views:

27

answers:

1

This should be easy: When calling a didSelectRowAtIndexPath, I run a complex method, that downloads the contents of a URL, parses it, and put the result in the various properties. In the Simulator, and on a device in a WiFi situation, everything is just fine. However, on a device on a slower network, it just takes some time to process this all. Therefore, I want to display a spinner in the cell of the selected row, to comfort the user in the idea that something is going on.

My problem is, that the spinner only seems to appear during the animated transition between the view in which a row was selected and the subsequent view.

I want the spinner to show during the downloading, the parsing and the animation.

I tried this:

- (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 myCustomCell = (MyCustomCell*)[tableView cellForRowAtIndexPath:indexPath];
 [myCustomCell.spinner startAnimating];
 return indexPath;
 }

and

- (NSIndexPath *)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
 myCustomCell = (EventCell*)[tableView cellForRowAtIndexPath:indexPath];
 [myCustomCell.spinner startAnimating];
 [self myVerySlowMethod];
 return indexPath;
 }

however, the spinner seems to be shown only in between the two views.

I tested this on a Real Device, and I never got the spinner to show.

Is this:

a) because the myVerySlowMethod is fast enough? b) because the didSelectRowAtIndexPath will first process everything and then do the display part or c) I should study all the well-written Programming Guides before I bother you?

Any answer is appreciated.

A: 

Hi, the problem is that in both cases, your [self myVerySlowMethod] (or equivalent) is blocking the main thread, and therefore the ActivityIndicator won't play.

The best approach on this is to run your myVerySlowMethod on a background thread, and then when it is finished it can call another method that pushes the new view controller onto the navigation stack.

First, call the method to run in the background:

[self performSelectorInBackground:(@selector(myVerySlowMethod)) withObject:nil];

This will automatically create a new background thread for you to run in. Then, you must make sure you do the following inside your background method:

-(void) myMethod {
   NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
   // code you want to run in background thread;
   [pool drain];
}

This is necessary because there isn't a default autorelease pool set up for any threads except the main one.

Finally, you'll want to push the new view controller onto the navigation stack on the main thread. If you have another method for this, call this from the background thread like so:

[self performSelectorOnMainThread:(@selector(myOtherMethod)) withObject:nil
                    waitUntilDone:YES];

The optional third parameter will hold up the main thread for you if you want do to other stuff after that.

Hope that helps!

h4xxr
Thanks, give me some time to digest this before I give you a Green Flag!
Sjakelien
I think this should do the trick. There's a new problem I'm running into right now, but I will post that as a separate question. Thanks.
Sjakelien