Выполните выборку, не замораживая пользовательский интерфейс - PullRequest
11 голосов
/ 11 января 2012

Я делаю небольшое приложение для чата.В моем приложении я использую NSFetchedResultsController.Есть 2 вида стола, 1 для лобби и 1 для чата.Проблема в том, что всякий раз, когда я захожу в чат, мне приходится ждать, пока NSFetchedResultsController выполнит выборку и загрузит все данные, прежде чем я смогу начать что-либо печатать.Мне было интересно, можно ли предварительно выполнить выборку в фоновом режиме или каким-либо образом позволить пользователю начать печатать до загрузки последних сообщений.

Так что, если я задаю эту часть в методе viewDidLoad, мой пользовательский интерфейс просто зависнет, пока все данные не будутзагружено:

NSError *_error;
if (![self.fetchedResultsController performFetch:&_error]) {
    NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]);
}

, и если я устанавливаю этот фрагмент кода в отдельный метод, а затем вызываю этот метод в viewDidLoad в фоновом режиме

[self performSelectorInBackground:@selector(fetchIt) withObject:nil];

tableView просто не обновляется, поэтому я имеювернуться к первому tableView, а затем вернуться, чтобы получить какие-либо результаты.

Спасибо.

Любая помощь будет признательна

обновление

Я попробовал несколько других способов сделать это.

Способ 1:

-(void)reloadTheTable
{
  [self.tableView reloadData];
}

-(void)fetchIt
{
  NSError *_error;
  if (![self.fetchedResultsController performFetch:&_error]) {
    NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]);
  }
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
  [self performSelectorOnMainThread:@selector(reloadTheTable) withObject:nil waitUntilDone:NO];
  [pool release];
}

- (void)viewDidLoad {
  //some code
  [self performSelectorInBackground:@selector(fetchIt) withObject:nil];
  //some other code
}

результат: tableView не показывает какие-либо данные, необходимо повторно открыть этоконтроллер представления

Способ 2:

- (void)viewDidLoad {
  //some code
  dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    NSError *_error;
    if (![self.fetchedResultsController performFetch:&_error]) {
        NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]);
    }
  });
  //some other code
}

результат: tableView обновляется, но пользовательский интерфейс зависает

Способ 3:

-(void)fetchIt
{
  NSError *_error;
  if (![self.fetchedResultsController performFetch:&_error]) {
    NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]);
  }
}

- (void)viewDidLoad {
  //some code
  [self performSelectorOnMainThread:@selector(fetchIt) withObject:nil waitUntilDone:NO];
  //some other code
}

результат: пользовательский интерфейс зависает, таблица обновлений.

Как я где-то читал, все, что связано с чем-тоПользовательский интерфейс должен быть сделан в главном потоке.Но я все еще не могу понять, как это сделать, не заморозив tableView.

Спасибо за чтение.

Любая помощь приветствуется

Ответы [ 5 ]

14 голосов
/ 13 января 2012

Я не уверен, сработает ли это или нет, но вы можете попробовать:

- (void)methodThatloadYourData {
  NSError *_error;
  if (![self.fetchedResultsController performFetch:&_error]) {
    NSLog(@"Unresolved error %@, %@", _error, [_error userInfo]);
  }
}

- (void)viewDidLoad {
  //some code

  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
                 ^{
                   [self performSelector:@selector(methodThatloadYourData)];
                   dispatch_async(dispatch_get_main_queue(),
                                    ^{
                                      [self.tableView reloadData];
                                    });
                 });

  //some other code
}
1 голос
/ 11 января 2012

Отправьте запрос на получение новой темы:

dispatch_queue_t coreDataThread = dispatch_queue_create("com.YourApp.YourThreadName", DISPATCH_QUEUE_SERIAL);

    dispatch_async(YourThreadName, ^{

Your Fetch Request

    });

    dispatch_release(YourThreadName);
1 голос
/ 11 января 2012

Установите для запроса выборки значение fetchBatchSize, чтобы фактически не получать все данные одновременно. Возможно, вам понадобится только достаточно записей, чтобы заполнить экран, и еще несколько, чтобы обеспечить адаптивную первоначальную прокрутку. Если речь идет, скажем, о сообщениях чата, я думаю, что ограничение выборки самыми последними 50 или 100 сообщениями должно значительно ускорить процесс.

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

Как только выборка будет выполнена в методе fetchIt, вызовите метод reloadData в UITableView. Для получения дополнительной информации см. Документацию Apple по UITableView

Edit:

- (void)controllerDidChangeContent:(NSFetchedResultsController *)controller {
    [self.tableView reloadData];
}

Для получения дополнительной информации посетите документацию Apple

0 голосов
/ 10 сентября 2015

Прежде всего, правильно индексируйте свойства объекта, чтобы запросы выполнялись быстрее, особенно при сортировке.Затем посмотрите на оптимизацию вашего запроса на выборку, установив размер пакета, ограничив данные до необходимого минимума.Используйте отладчик SQL, чтобы проверить запрос, и даже протестировать запросы самостоятельно, используя приложение типа Base.Если вы попытаетесь использовать многопоточность без необходимости для такого простого приложения, это только усугубит ситуацию.

К вашему сведению в вашем коде, viewDidLoad уже находится в главном потоке.Если вы пытаетесь отложить выборку до тех пор, пока не загрузится представление, вы можете использовать executeSelector afterDelay: 0.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...