Activity indicator (spinner) with UIActivityIndicatorView

社会主义新天地 提交于 2019-12-04 08:44:40

问题


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

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

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

I'd like to have the spinner to show on the top bar at the app launch and dissapear once the data is displayed on my tableView.

I thought that putting the beginning at viewDidAppear and the end at -(void)parserDidEndDocument:(NSXMLParser *)parser but it didn't work.

I'd appreciate a good explained solution on how to implement this solution.


回答1:


Here's the problem: NSXMLParser is a synchronous API. That means that as soon as you call parse on your NSXMLParser, that thread is going to be totally stuck parsing xml, which means no UI updates.

Here's 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've used this method many times, and it works beautifully.




回答2:


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 !




回答3:


I typically implement an NSTimer that will call my spinner method, which I fire off right before I go into doing the heavy work (the work that will typically block the main thread).

The NSTimer fires and my spinner method is called. When the main work is finished, I disable the spinner.

Code for that is like:

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];



回答4:


In Cocoa (and most other app frameworks) the user interface is updated by the main thread. When you manipulate views, they are typically not redrawn until control returns to the run loop and the screen is updated.

Because you are parsing the XML in the main thread, you are not allowing the screen to update, and that is why your activity indicator is not appearing.

You should be able to fix it by doing the following:

  1. In viewDidAppear, show/animate the spinner and then call

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

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

This way, control will return to the run loop before parsing begins, to allow the spinner to begin animating.



来源:https://stackoverflow.com/questions/2262738/activity-indicator-spinner-with-uiactivityindicatorview

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!