UIActivityIndicatorView won't stop

2019-05-09 00:26发布

问题:

I'm playing with some JSON parsing in iOS and i wanted to add a spinner, this works wel but i can't stop the spinner and i would like to understand why.

[spinner stopAnimating] is called in the async block and i believe thats where the problem is, maybe because i can't call the method on spinner in the block? i've logged the spinner obj and the output is:

<UIActivityIndicatorView: 0x76905f0; frame = (150 230; 20 20); layer = <CALayer: 0x768ffb0>>

Maybe somebody can make me understand how to deal with this async methods in objective-c. I'm a absolute beginner.

The code:

- (void)viewDidLoad{
  [super viewDidLoad];

  UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
  spinner.center = CGPointMake(160, 240);
  [self.view addSubview:spinner];
  [spinner startAnimating];


  dispatch_async(kBgQueue, ^{

    NSData* data = [NSData dataWithContentsOfURL:
                    kLatestKivaLoansURL];
    [self performSelectorOnMainThread:@selector(fetchedData:)
                           withObject:data waitUntilDone:YES];
     NSLog(@"loans: %@", spinner);
     [spinner stopAnimating];
  });


}

回答1:

Never never never (never!) talk to the interface on a background thread. What you want is to jump back into the main thread - as you rightly suspect. It's easy-peasy:

[spinner startAnimating];
dispatch_async(kBgQueue, ^{
    NSData* data = [NSData dataWithContentsOfURL:
                    kLatestKivaLoansURL];
    // ... do other stuff in the background
    dispatch_async(dispatch_get_main_queue(), ^{
        [spinner stopAnimating];
    });
});

However, your use of performSelectorOnMainThread:withObject:waitUntilDone: with waitUntilDone:YES is also wrong (or at least a very bad smell), since you should not be blocking on your background thread. Just call a method right here on the background thread (unless it touches the interface) and when the result comes back, it comes back.



回答2:

also call the method removeFromSuperview after stopAnimating

    [spinner stopAnimating];
    [spinner removeFromSuperview];


回答3:

UIKit calls can only be made in the main thread. Try this:

dispatch_async(kBgQueue, ^{

     NSData* data = [NSData dataWithContentsOfURL:kLatestKivaLoansURL];
    [self performSelectorOnMainThread:@selector(fetchedData:)
                       withObject:data waitUntilDone:YES];
     NSLog(@"loans: %@", spinner);

     dispatch_async(dispatch_get_main_queue(), ^{

         [spinner stopAnimating];

     });
});