2013-06-27 4 views
7

В моем приложении у меня есть UITableViewController.Обновить данные UITableView в фоновом режиме

Его таблицаView разделена на 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.

Благодарим за помощь.

EDIT

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

Вот рабочий раствор:

Как MROS suggets, я удалил очереди отправки из 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 и указать приоритет, чтобы фактически получить другой поток. Кроме того, отправка async в viewDidLoad бесполезна, так как все методы жизненного цикла контроллера контроллера вызывают в основном потоке. Я бы рекомендовал сделать что-то в ваших методах f1, f2 и f3:

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

2

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

dispatch_queue_t concurrentQueue = dispatch_get_main_queue(); 

To:

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

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

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

Вы создали параллельный вызов? – abhi1992

3

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

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

Вы хотите завершить трудоёмкие загрузки данных вещей в фоновом потоке, а затем обновить UI/Cells, когда ваши данные будут готовы в основном потоке.

Как так:

-(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 
    }); 
} 
+0

Я пробовал ваше решение, но пользовательские взаимодействия и перезагрузка блокируют друг друга. Я имею в виду, что reloadDatas не вызывается, так как пользователь не остановил прокрутку таблицы, и пользователь не может прокручивать таблицу, пока таблица не обновляется ... – zbMax

+0

Вы уверены, что ее не вызывают, потому что пользователь прокручивает таблицу ? Попробуйте добавить несколько NSLogs или контрольных точек. – smaura777

+0

да, это то, что я подразумеваю под «пользовательскими взаимодействиями»: при прокрутке таблицы мой NSTimer не вызывает мою функцию до тех пор, пока прокрутка не закончится. – zbMax

1

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

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

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

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

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

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

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

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