Исходя из вашего ответа в комментариях к вопросу, звучит так, как будто вы вызываете [tableView reloadData] из фонового потока.
Не делайте этого. Методы UIKit, если не указано иное, всегда необходимо вызывать из основного потока. Невыполнение этого требования не может привести к концу проблем, и вы, вероятно, видите одну из них.
РЕДАКТИРОВАТЬ: я неправильно прочитал ваш комментарий. Похоже, вы не обновляете пользовательский интерфейс из фонового потока. Но мои комментарии об архитектуре (т.е. почему вы обновляете в фоновом потоке ПОСЛЕ окончания загрузки?).
Вы утверждаете, что "когда данные возвращаются с сервера, я вызываю фоновую операцию ..." Это звучит задом наперед. Обычно вы должны запускать NSURLConnection (или то, что вы используете для загрузки) в фоновом потоке, чтобы не блокировать пользовательский интерфейс, а затем вызывать основной поток для обновления модели данных и обновления пользовательского интерфейса. В качестве альтернативы используйте асинхронный NSURLConnection (который управляет своим собственным фоновым потоком / очередью), например ::
[NSURLConnection sendAsynchronousRequest:(NSURLRequest *)
requestqueue:(NSOperationQueue *)queue
completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler];
И просто убедитесь, что используете [NSOperationQueue mainQueue] для очереди.
Вы также можете использовать GCD, то есть вложенные вызовы dispatch_async () (внешние по отношению к фоновой очереди для обработки синхронного соединения, внутренние в главной очереди для обработки ответа на соединение).
Наконец, я отмечу, что вы в принципе можете обновить свою модель данных в фоновом потоке и просто обновить интерфейс пользователя из основного потока. Но это означает, что вам нужно позаботиться о том, чтобы сделать код модели потокобезопасным, что вы, вероятно, испортите хотя бы пару раз. Поскольку обновление модели, вероятно, не занимает много времени, я бы просто сделал это и в главном потоке.
EDIT:
Я добавляю пример того, как можно использовать GCD и синхронные запросы для достижения этой цели. Ясно, что есть много способов выполнить неблокирующие URL-запросы, и я не утверждаю, что это лучший. Это, на мой взгляд, позволяет хранить весь код для обработки запроса в одном месте, что облегчает его чтение.
В коде много неровностей. Например, создание пользовательской очереди отправки обычно не требуется. Он слепо предполагает кодировку UTF-8 возвращаемой веб-страницы. И ни один контент (кроме описания ошибки HTTP) не локализован. Но он демонстрирует, как выполнять неблокирующие запросы и обнаруживать ошибки (как на уровне сети, так и на уровне HTTP). Надеюсь, что это полезно.
NSURL *url = [NSURL URLWithString:@"http://www.google.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
dispatch_queue_t netQueue = dispatch_queue_create("com.mycompany.netqueue", DISPATCH_QUEUE_SERIAL);
dispatch_async(netQueue,
^{
// We are on a background thread, so we won't block UI events (or, generally, the main run loop)
NSHTTPURLResponse *response;
NSError *error;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
dispatch_async(dispatch_get_main_queue(),
^{
// We are now back on the main thread
UIAlertView *alertView = [[UIAlertView alloc] init];
[alertView addButtonWithTitle:@"OK"];
if (data) {
if ([response statusCode] == 200) {
NSMutableString *body = [[NSMutableString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
[alertView setTitle:@"Success"];
[alertView setMessage:body];
}
else {
[alertView setTitle:@"HTTP Error"];
NSString *status = [NSHTTPURLResponse localizedStringForStatusCode:[response statusCode]];
[alertView setMessage:status];
}
}
else {
[alertView setTitle:@"Error"];
[alertView setMessage:@"Unable to load URL"];
}
[alertView show];
[alertView release];
});
});
dispatch_release(netQueue);
EDIT:
О, еще один большой грубый край. Приведенный выше код предполагает, что любой код состояния HTTP! = 200 является ошибкой. Это не обязательно так, но решение этого вопроса выходит за рамки этого вопроса.