简体   繁体   中英

NSoperationQueue blocking main thread

So, obviously I am doing something wrong here. I have an app that uses MVC and in one of my model classes I have a call to a web service which could take some time to process. The view controller calls a method in the model class which starts the download process. The download process is performed through an AFHTTPRequestOperation which is placed in an NSOperationQueue. The entire download process happens in the model class, outside of the view controller. However, the download operation appears to block the main thread as the UI becomes unresponsive during the operation. I have hardcoded a pause to simulate a slow network. When the operation completes, it calls the view controller through a delegate method. This code works, but as I mentioned, it blocks the main thread.

In my model class (StreamGauge) I have the following:

-(void)getGaugeReadings{

    NSString *endpointURL = [NSString stringWithFormat:@"http://...", stationID_, timeSpan_];

    NSURL *url = [NSURL URLWithString:endpointURL];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
    [operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject){
        NSData *data = (NSData*)responseObject;
        [self processXmlObject:data];
        [self setGaugeFlowKeys:[self getFlowKeys]];
        [NSThread sleepForTimeInterval:3];
        [self.delegate updateGaugeTable];
    }failure:^(AFHTTPRequestOperation *operation, NSError *err){
        NSLog(@"ERROR: %@", [err localizedDescription]);
    }];

    NSOperationQueue *gaugeDownloadQueue = [[NSOperationQueue alloc] init];
    [gaugeDownloadQueue setName:@"Gauge_Download"];
    [gaugeDownloadQueue addOperation:operation];
}

In my view controller I have the following in my viewDidLoad (with hardcoded parameters):

- (void)viewDidLoad
{
    [super viewDidLoad];
    gauge = [[StreamGauge alloc] initWithStationID:@"A3185AX400" forTimeSpan:24];        
    [gauge setDelegate:self];
    [gauge getGaugeReadings];
}

I am more accustomed to using GCD for stuff like this, but now I need the ability to cancel the operation after a timeout has expired, so NSOperationQueue is more appropriate, but obviously my lack of a thorough understanding of operation queues is an issue here.

Could there be any issues with placing this background operation in a model class? Should background operation always be in controller classes? Anything else I am doing wrong here?

The problem is that you are not retaining gaugeDownloadQueue . So it just vanishes in a puff of smoke and everything happens on the main thread. (And you won't be able to cancel anything, because you have no reference to any operation queue.)

You need to retain gaugeDownloadQueue in a persistent reference (eg an instance variable / property). Otherwise it is useless to you, in more ways than one.

Also, what thread is your AFHTTPRequestOperation completion block being called on? If it's a background thread, and you are doing stuff to the interface (eg your call to updateGaugeTable , that will certainly cause trouble). The fact that you are using NSOperation does not at all free your from responsibility for worrying about what thread you're on.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM