0

Итак, очевидно, что я делаю что-то не так. У меня есть приложение, которое использует MVC, и в одном из моих классов моделей у меня есть вызов веб-сервиса, который может занять некоторое время для обработки. Контроллер вида вызывает метод в классе модели, который запускает процесс загрузки. Процесс загрузки выполняется через AFHTTPRequestOperation, который помещается в NSOperationQueue. Весь процесс загрузки происходит в классе модели, вне контроллера представления. Тем не менее, операция загрузки, по-видимому, блокирует основной поток, поскольку пользовательский интерфейс становится неактуальным во время операции. Я жестко закодировал паузу, чтобы имитировать медленную сеть. Когда операция завершается, она вызывает контроллер вида через метод делегата. Этот код работает, но, как я уже упоминал, он блокирует основной поток.NSoperationQueue блокирует основную нить

В моей модели классе (StreamGauge) У меня есть следующий:

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

На моем взгляде, контроллер У меня есть следующий в моей viewDidLoad (с закодированными параметрами):

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

Я больше привык к использованию GCD для таких вещей, но теперь мне нужна возможность отменить операцию после истечения тайм-аута, поэтому NSOperationQueue более уместен, но, очевидно, проблема в том, что я недостаточно разбираюсь в операционных очередях.

Не могли бы возникнуть проблемы с размещением этой фоновой операции в классе модели? Должна ли фоновая операция всегда находиться в классах контроллера? Что-нибудь еще я делаю неправильно здесь?

ответ

1

Проблема в том, что вы не сохраняете gaugeDownloadQueue. Так что он просто исчезает в дымке, и все происходит на главной нитке. (А вы не сможете отменить что-либо, потому что у вас нет ссылки на какие-либо очереди операций.)

Вы должны сохранить gaugeDownloadQueue в постоянная ссылках (например, экземпляр переменная/собственности). В противном случае это бесполезно для вас, более чем одним способом.

Кроме того, в какой поток входит ваш блок завершения AFHTTPRequestOperation? Если это фоновый поток, и вы делаете материал для интерфейса (например, ваш звонок updateGaugeTable, это наверняка вызовет проблемы). Тот факт, что вы используете NSOperation, вовсе не освобождает вас от ответственности за то, что вы беспокоитесь о том, какой поток вы используете.

+0

Вот пример того, как использовать NSOperation/NSOperationQueue, чтобы сделать что-то в фоновом режиме: https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch25p865mandelbrotOperation/ch38p1106mandelbrotNoThreading/MyMandelbrotView.m – matt

+0

Это имеет смысл, но по-прежнему, похоже, блокирует основной поток. Пользовательский интерфейс по-прежнему не отвечает, пока не вернется служебный вызов. – Pheepster

+0

Хорошо, но вы используете некоторые классы, отличные от Cocoa, о которых я ничего не знаю (например, AFHTTPRequestOperation), так как я знаю, что вы не злоупотребляете ими? Например, у вас есть блок завершения в вашем AFHTTPRequestOperation, но как узнать, какой поток вызван? Если это фоновый поток, и вы делаете материал для интерфейса, это, безусловно, вызовет проблемы. – matt

Смежные вопросы