Перезагружать данные в 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 и отправляете уведомление, чтобы позволить таблице обновиться.
довольно стандартный рецепт.