views:

49

answers:

2

Hi all,

I have an app that performs some calculations based on data arriving on a socket or local user interaction.

I want to show an 'activity spinner' whilst the calculation happens.

spinner = [[UIActivityIndiactorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[spinner setCenter:self.view.center];
[self.view addSubview:spinner];
[spinner startAnimating];
[self performSelector:@selector(doCalcs) withObject:nil afterDelay:0];

This works well, except in the case where the code is run as a result of a message arriving over the network. I'm using http://code.google.com/p/cocoaasyncsocket/ to handle sockets and the code is running in the onSocket:didReadData:withTag: method.

'doCalcs' takes a few seconds. The spinner doesn't appear whilst it's running.

If I change afterDelay:0 to afterDelay:1 then the spinner does appear the whole time doCalcs is running, but with the downside that it takes an extra second. So it seems the code is all correct, but for whatever reason the spinner isn't getting a chance to get on screen before doCalcs runs.

Any suggestions would be most welcome.

A: 

Instead of a selector, you need to spawn a thread to do your calculations. UI Only updates if the app allows trips through the event loop. and your method is blocking. Alternatively, you can have a timer call your "doCalcs" method periodically until they are complete... it should exit after a set period of time so the event loop can execute and do the calcs in "slices". If you need further direction let me know!

Kenny
+1  A: 

You could try doing your calculations on a background thread to prevent the animation from blocking:

[self performSelectorInBackground:@selector(doCalcs)withObject:nil];
Jason Jenkins
Thanks, that seems like a reasonable alternative. I still feel there's something that's unclear about the order that performSelector() and view updates happen in, but I guess that's undocumented / not-guaranteed.
JosephH