Итак, очевидно, что я делаю что-то не так. У меня есть приложение, которое использует 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 более уместен, но, очевидно, проблема в том, что я недостаточно разбираюсь в операционных очередях.
Не могли бы возникнуть проблемы с размещением этой фоновой операции в классе модели? Должна ли фоновая операция всегда находиться в классах контроллера? Что-нибудь еще я делаю неправильно здесь?
Вот пример того, как использовать NSOperation/NSOperationQueue, чтобы сделать что-то в фоновом режиме: https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/bk2ch25p865mandelbrotOperation/ch38p1106mandelbrotNoThreading/MyMandelbrotView.m – matt
Это имеет смысл, но по-прежнему, похоже, блокирует основной поток. Пользовательский интерфейс по-прежнему не отвечает, пока не вернется служебный вызов. – Pheepster
Хорошо, но вы используете некоторые классы, отличные от Cocoa, о которых я ничего не знаю (например, AFHTTPRequestOperation), так как я знаю, что вы не злоупотребляете ими? Например, у вас есть блок завершения в вашем AFHTTPRequestOperation, но как узнать, какой поток вызван? Если это фоновый поток, и вы делаете материал для интерфейса, это, безусловно, вызовет проблемы. – matt