UITableView Обновить данные - PullRequest
       1

UITableView Обновить данные

1 голос
/ 26 января 2012

У меня есть UITableViewController, при открытии которого отображается таблица следующего объекта:

class {
  NSString *stringVal;
  int value;
}

Однако, когда этот контроллер открывается, я хочу, чтобы он загружал данные из Интернета и отображал «Подключение... »в строке состояния и обновите stringVal и значение всех объектов.Я делаю это, обновляя массив в UITableViewController.Однако для этого пользовательский интерфейс иногда зависает или даже отображает «пустые» ячейки таблицы, пока операция не завершится.Я делаю это NSOperationQueue для загрузки данных, но мне интересно, есть ли лучший способ обновить данные без этих странных ошибок пользовательского интерфейса.

РЕДАКТИРОВАТЬ:

Пользовательский интерфейс больше не отображает пустые ячейки.Это было потому, что cellForRowAtIndexPath устанавливал нулевые значения для моего cellText.Однако при вызове tableView.reloadData он все еще выглядит несколько медленным, хотя я использую NSOperationQueue.

EDIT2:

Более того, у меня есть две проблемы:обновляется и 2. когда прокрутка останавливается и пользовательский интерфейс начинает обновляться, он немного зависает.Прекрасный пример того, что я пытаюсь сделать, можно найти в собственном приложении Почта, когда вы просматриваете список папок с их непрочитанным количеством.Если вы постоянно прокручиваете просмотр таблицы, счетчик непрочитанных папок будет обновляться без каких-либо зависаний.

1 Ответ

0 голосов
/ 26 января 2012

Исходя из вашего ответа в комментариях к вопросу, звучит так, как будто вы вызываете [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 является ошибкой. Это не обязательно так, но решение этого вопроса выходит за рамки этого вопроса.

...