8

I am running creating an iPhone application which performs a costly operation and I wanted to create an activityIndicator to let the user know the application has not frozen.

The operation is performed entirely in one event call... so there is no chance for the UI framework to receive control to actually display and animate this indicator.

The sample apps which use the UIActivityIndicator (or any other similar animation) start and stop the animation in different events, triggered separately at different stages of the program.

Do I need to manually create a separate thread to run my operation in, or is there already default support for this kind of behavior?

5 Answers 5

13

I just found someone asking a very similar question with a good answer on the apple iPhone forums. https://devforums.apple.com/message/24220#24220 #Note: you have to have an appleID to view it.

Essentially, yes, you do need to start your process running in a different thread, but its quite easy to do (as paraphrased from user 'eskimo1')

- (IBAction)syncOnThreadAction:(id)sender { [self willStartJob]; id myObject = [MyObjectClass createNewObject]; [self performSelectorInBackground: @selector(inThreadStartDoJob:) withObject:myObject ]; } - (void)inThreadStartDoJob:(id)theJobToDo { NSAutoreleasePool * pool; NSString * status; pool = [[NSAutoreleasePool alloc] init]; assert(pool != nil); status = [theJobToDo countGrainsOfSandOnBeach]; [self performSelectorOnMainThread: @selector(didStopJobWithStatus:) withObject:status waitUntilDone:NO ]; [pool drain]; } 

where -willStartJob and -didStopJobWithStatus are my own methods that:

  • disable the UI, to prevent the user from kicking off two jobs at once
  • set up the activity indicator
Sign up to request clarification or add additional context in comments.

6 Comments

i think my problem is similar like yours, can you tell me what do you mean with status = [... do long running job specified by theJobToDo ...], i dont get it, can you give me an example?
inThreadStartDoJob runs in a different thread, so I simply meant you could perform any series of complicated, long running operations in that thread. I've updated the answer with a simple example
i dont understand what is theJobToDo in this line : [self performSelectorInBackground: @selector(inThreadStartDoJob:) withObject:theJobToDo ]; ?? is it global variable?
It's just a placeholder name I made up when writing the question, so yes, I guess in that context it would be a variable declared elsewhere (or globally).
is the implementation of countGrainsOfSandOnBeach method is on the same class?
|
9

Yes, you need to put your operation in a separate thread while the UIActivityIndicatorView calls remain on the main thread.

Here's why: If you start animating your indicator view then immediately begin your process, your process will block until finished, and the user will never see any "activity."

Instead, start animating the indicator, then pop a new thread for your process. Use notifications, a delegate pattern, or performSelectorOnMainThread:withObject:waitUntilDone: to let the main thread know that the process is finished. Then stop the animation and continue.

This will ensure that the user knows something is happening while your process does its thing.

1 Comment

A developer does not need to put their operation in a separate thread. Instead they should weigh their options and make the best choice -- if the operation will take a few seconds, and spawning a new thread will generate notable user interface conflicts, blocking on the main thread with an activity indicator is a better option. Additional threads need to be added to an application with respect, understanding and care.
4

Starting a new thread can be overkilling and a source of complexity if you want to do things that are supposed to start on the main thread.

In my own code, I need to start a MailComposer by pushing a button but it can take some time to appear and I want to make sure the UIActivityIndicator is spinning meanwhile.

This is what I do :

-(void)submit_Clicked:(id)event { [self.spinner startAnimating]; [self performSelector:@selector(displayComposerSheet) withObject:nil afterDelay:0]; } 

It will queue displayComposerSheet instead of executing it straight away. Enough for the spinner to start animating !

1 Comment

When an application is already making heavy use of threads -- adding yet another thread can make matters quite unruly. Sometimes it is ok to block on the main thread -- it can be an effective alternative for many operations.
-1

An UIProgressView (the progress bar) can not run by itself, you need to periodically increment its value.

An UIActivityIndicatorView (the spinning gear) can run by itself: just call startAnimating when you start your operation and stopAnimating when you're done.

So an UIActivityIndicatorView may be what you're looking for.

Comments

-1

Which is easier:

1> Have 1 method that starts the spinner (in the background). 2> Run your long-running code right here. 3> Have 1 method that ends the spinner. 

or....

A> Have 1 method that starts the spinner. B> Have 20 methods (1 for each thing you want to do in the background) C> Have 1 method that ends the spinner. 

I always see everyone suggest A,B,C... the hard way.

2 Comments

Can you clarify which threads are being used for each of (1,2,3,A,B,C) steps.
The spinner stops while "2>Run your long-running code right here" is running resulting in the user never seeing spin.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.