Перезагружать данные в UITableView в фоновом режиме

в моем приложении, у меня есть UITableViewController.

его tableView разделен на 3 секции.

загрузить данные для каждого из этих разделов с моего сервера. Для этого у меня есть 3 функции (например, f1 f2 и f3). Каждый обновляет соответствующий NSArray, используемый в качестве источника данных для моей таблицы.

теперь я хочу перезагрузить данные, используя эти функции, и обновить мой tableView, как только эти 3 функции будут выполнены, но не нарушая пользователь.

Я не используется с асинхронным запросом, блоками, потоками и т. д... и я ищу чаевые.

на самом деле, вот что я делаю :

-(void)viewDidLoad
{
    //some settings

    [NSTimer scheduledTimerWithTimeInterval:15.0 target:self selector:@selector(reloadDatas) userInfo:nil repeats:YES];

    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        [self reloadDatas];
    });
}

-(void)reloadDatas
{
    dispatch_queue_t concurrentQueue = dispatch_get_main_queue();
    dispatch_async(concurrentQueue, ^{
        [self f1];
        [self f2];
        [self f3];
        [myDisplayedTable reloadData];
    });
}

-(void)f1
{
    //load datas with a url request and update array1
}
-(void)f2
{
    //load datas with a url request and update array2
}
-(void)f3
{
    //load datas with a url request and update array3
}

но здесь мой tableView "заморожен", пока он не будет обновлен.

меня не волнует порядок выполнения f1 f2 и f3, но мне нужно подождать, пока эти 3 функции будут выполнены, прежде чем обновлять мой tableView.

спасибо помощь.

редактировать

Спасибо за все ваши ответы.

вот рабочее решение:

как предлагает mros, я удалил очередь отправки из viewDidLoad и заменил в reloadDatas:

dispatch_queue_t concurrentQueue = dispatch_get_main_queue();

С

dispatch_queue_t mainThreadQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

и, наконец, я перезагружаю свою таблицу в основной поток

dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });

4 ответов


таким образом, ваш" фоновый поток " на самом деле является вашим основным потоком. Вы должны использовать dispatch_get_global_queue и указать приоритет, чтобы фактически получить другой поток. Кроме того, асинхронная отправка в viewDidLoad бесполезна, поскольку все методы жизненного цикла контроллера представления вызываются в основном потоке. Я бы рекомендовал сделать что-то следующее в ваших методах f1, f2 и f3:

начните с запуска асинхронного запроса url, затем в блоке завершения обновите arrayX и перезагрузите конкретный раздел вашего tableview. Таким образом, все три запроса могут выполняться одновременно, и таблица просто обновляет необходимые данные, когда каждый из них заканчивается. Кроме того, если вы хотите перезагрузить только один раз, просто замените переменную concurrentQueue на фоновый поток, а затем выполните [tableView reloadData] в основном потоке.


предыдущие ответы абсолютно верны. Однако ваша реализация reloadDatas & viewDidLoad немного проблематична.

просто для уточнения:

вы хотите завершить трудоемкую загрузку данных в фоновом потоке, а затем обновить пользовательский интерфейс/ячейки, когда ваши данные будут готовы в основном потоке.

вот так:

  -(void)viewDidLoad
    {
       dispatch_queue_t concurrentQueue = dispatch_queue_create("com.my.backgroundQueue", NULL);
        dispatch_async(concurrentQueue, ^{
            [self reloadDatas];
        });
    }

-(void)reloadDatas
{
    // Expensive operations i.e pull data from server and add it to NSArray or NSDictionary
      [self f1];
      [self f2];
      [self f3];

    // Operation done - now let's update our table cells on the main thread  

    dispatch_queue_t mainThreadQueue = dispatch_get_main_queue();
    dispatch_async(mainThreadQueue, ^{

        [myDisplayedTable reloadData]; // Update table UI
    });
}

на reloadDatas способ вы должны изменить эту строку:

dispatch_queue_t concurrentQueue = dispatch_get_main_queue();

в:

dispatch_queue_t concurrentQueue = dispatch_queue_create("some queue", NULL);

но когда вы называете [myDisplayedTable reloadData], вам нужно вызвать эту операцию в главной очереди.

dispatch_async(dispatch_get_main_queue(), ^{ [myDisplayedTable reloadData]; });

еще одна вещь. Извлечение данных с сервера и обновление ячеек таблицы довольно распространено. Здесь не нужны очереди или таймеры. Вот альтернативная структура.

скажем, вы тянете mp3 с вашего сервера : Ваш класс модели: музыка.h / m Ваш менеджер моделей: MusicManager.h / m (Singleton) - он будет содержать массив музыкальных объектов - этот синглтон в основном является вашим источником данных; и, наконец, ваш UItableViewController: MusicTableVC.h / m

In MusicManager.h / m : у вас есть NSMutableArray который будет загружен музыкой.H объекты, которые вы извлекли с сервера. Вы можете сделать это, как только приложение загрузится, даже не дожидаясь TableViewController.

внутри MusicManager у вас есть несколько вспомогательных методов для добавления или удаления элементов из mutableArray и предоставления подсчета и, конечно же, ваших сетевых методов.

наконец: опубликуйте уведомление в своем сетевом коде. Ваш UITableViewController следует слушать / соблюдать это уведомление и" перезагружать " соответственно.

 [[NSNotificationCenter defaultCenter] postNotificationName:@"NewMusicAdded" object:nil];

вы запрашиваете данные с вашего сервера, анализируете данные в музыкальные объекты, добавляете их в массив NSMutable и отправляете уведомление, чтобы позволить таблице обновиться.

довольно стандартный рецепт.