Search code examples
iosgrand-central-dispatchnsoperationnsoperationqueue

NSOperationQueue seems to slow performance


I am new to NSOperationQueue, but in a current project I need a way to cancel an asynchronous operation when it times out. My original code uses GCD and works. Here it is:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),^{
    rg = [[RiverGauge alloc] initWithStationInfo:[station id] forHistoryInHours:48 inThisFormat:nil];
    dispatch_async(dispatch_get_main_queue(), ^{
        [hud removeFromSuperview];
        UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
        GaugeViewController *vc = [sb instantiateViewControllerWithIdentifier:@"GaugeDetailViewController"];
        [vc setRiverGauge:rg];
        [self.navigationController pushViewController:vc animated:YES];
    });
});

RiverGauge is a network operation that could take a long time, especially if the user is in rural areas. Most posts I've seen suggest moving this into an NSOperationQueue. I have done so as follows:

NSOperationQueue *queue = [NSOperationQueue new];
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(getGaugeDetail:) object:[station id]];
[queue addOperation:op];

In the getGaugeDetail method (in the selector parameter) I have the following code:

RiverGauge *rg = [[RiverGauge alloc] initWithStationInfo:gaugeIdentifier forHistoryInHours:48 inThisFormat:nil];
UIStoryboard *sb = [UIStoryboard storyboardWithName:@"Main" bundle:nil];
GaugeViewController *vc = [sb instantiateViewControllerWithIdentifier:@"GaugeDetailViewController"];
[vc setRiverGauge:rg];
[self.navigationController pushViewController:vc animated:YES];

When doing this operation using GCD, it responds quickly with a fast internet connection. However, when using NSOperationQueue, the same operation takes several seconds. The returned data is accurate, however. Again, I'm not very familiar with NSOperationQueue. Any suggestions?

Thanks!


Solution

  • In your code when using an NSOperationQueue, it looks like you're making your UI changes in the NSOperationQueue, which would presumably be performing these on a thread other than the main thread. Sometimes when you interact with UIKit elements off the main thread, they either don't work correctly or there's a noticeable delay before the results of them appear. So my guess is that you're seeing the effects of making UI changes on the wrong thread.

    Try performing the UIKit stuff back on the main thread and see if it seems to fix your issue. You can probably continue to use GCD to do that.