Activity indicator (counter) using UIActivityIndicatorView

I have a tableView that loads an XML stream as follows:

- (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; if ([stories count] == 0) { NSString *path = @"http://myurl.com/file.xml"; [self parseXMLFileAtURL:path]; } } 

I would like the spinner to appear on the top bar when the application starts and disappear as soon as the data is displayed on my table.

I thought putting a start in viewDidAppear and ending with -(void)parserDidEndDocument:(NSXMLParser *)parser , but that didn't work.

I would appreciate a good explanation of how to implement this solution.

+4
source share
4 answers

Here's the problem: NSXMLParser is a synchronous API. This means that as soon as you call parse on NSXMLParser , this thread will completely loop into xml parsing, which means there are no user interface updates.

Here is how I usually solve this:

 - (void) startThingsUp { //put the spinner onto the screen //start the spinner animating NSString *path = @"http://myurl.com/file.xml"; [self performSelectorInBackground:@selector(parseXMLFileAtURL:) withObject:path]; } - (void) parseXMLFileAtURL:(NSString *)path { //do stuff [xmlParser parse]; [self performSelectorOnMainThread:@selector(doneParsing) withObject:nil waitUntilDone:NO]; } - (void) doneParsing { //stop the spinner //remove it from the screen } 

I have used this method many times and it works great.

+5
source

Starting a new thread can be overwhelming and a source of complexity if you want to do what needs to start in the main thread.

In my own code, I need to run MailComposer by clicking a button, but it may take some time for me to appear, and I want to make sure that the UIActivityIndicator works from time to time.

This is what I do:

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

It will queue up for displayComposerSheet instead of executing it immediately. Enough for the spinner to start the animation!

+3
source

I usually use NSTimer, which will call my spinner method, which I start right before starting to do the hard work (work that usually blocks the main thread).

NSTimer is called and my spinner method is called. When the main work is finished, I will turn off the counter.

Code for this:

 IBOutlet UIActiviyIndicatorView *loginIndicator; { ... [loginIndicator startAnimating]; [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(executeAuthenticationRequest) userInfo:nil repeats:NO]; ... } - (void) executeAuthenticationRequest { /* Simulate doing a network call. */ sleep(3); [loginIndicator stopAnimating]; ... } 

You can also do:

 IBOutlet NSProgressIndicator *pIndicator; 

Start:

 [pIndicator startAnimation:self]; [pIndicator setHidden:NO]; 

And Stop:

 [pIndicator stopAnimation:self]; [pIndicator setHidden:YES]; 
+2
source

In Cocoa (and most other application infrastructures), the user interface is updated with the main thread. When you manipulate views, they usually do not redraw until after the control returns to the execution loop and the screen is refreshed.

Since you parse the XML in the main thread, you do not allow the screen to refresh, and therefore the activity indicator does not appear.

You can fix this by doing the following:

  • In viewDidAppear, show / animate the counter, and then call

    [self performSelector: @selector (myXMLParsingMethod) withObject: nil afterDelay: 0];

  • In myXMLParsingMethod, parse your XML, then hide / stop the spinner.

In this way, control will return to the run loop before parsing begins to allow the counter to start the animation.

+1
source

Source: https://habr.com/ru/post/1301279/


All Articles