У меня есть UITableViewController
, о котором я хотел бы уведомить, когда данные соответствующей модели будут готовы для отображения. Проблема заключается в том, что эти данные извлекаются из веб-службы, и запрос может занять до нескольких секунд. В настоящее время я синхронно извлекаю данные из основного потока, что, естественно, приводит к блокировке основного потока. Теперь я не хочу, чтобы мой контроллер знал что-либо о загрузке данных из Интернета. Как я могу сделать это. В настоящее время я думаю об использовании GCD и реализации такого метода, как -loadDataWithCallback:
, и о предоставлении обратного вызова, который запускает [tableView reloadData]
в случае успеха. Это хороший подход? Есть ли другие возможности уведомить контроллер о том, что модель готова? У меня была другая идея - использовать механизм делегирования и установить контроллер в качестве делегата моей модели?
Подводя итог, что лучше: GCD с обратными вызовами или реализация собственного механизма делегатов?
Есть ли другие возможности?
Обновление : 24 июня 2011 г. 13:15 CET
После прочтения всех ваших ответов я прихожу к выводу, что есть 3 возможных решения моей проблемы:
Используйте NSNotifications
и используйте NSURLConnection
для реализации асинхронного. скачать
Реализация пользовательского протокола и использование механизма делегирования. Опять же, используйте NSURLConnection
для реализации асинхронного. скачать.
Использовать синхронную загрузку в отдельной очереди GCD и использовать обратные вызовы.
Поскольку никто не одобряет последнее решение, я хочу обсудить этот подход немного глубже. После просмотра всего кода, который задействован в обработке уведомлений, я думаю, что GCD - лучший подход. Вместо согласования определенного уведомления, которое должно быть каким-то образом задокументировано, чтобы каждый разработчик знал об этом, я могу просто использовать обратный вызов. С одной стороны, он дает мне понятный интерфейс, подобный тому, который был бы у меня при использовании делегата, с другой стороны, он дает мне полную гибкость. Вы действительно думаете, что GCD слишком сложен для этого? Вот мой код:
- (void)loadRestaurantsWithCallback:(void (^)())callback
{
dispatch_queue_t current_queue = dispatch_get_current_queue();
dispatch_queue_t download_queue = dispatch_queue_create("Download queue", NULL);
dispatch_async(download_queue, ^{
self.restaurants = [self loadRestaurants];
dispatch_async(current_queue, ^{ callback(); });
});
dispatch_release(download_queue);
}
Кстати, мое приложение просто отображает меню разных столовых в моем университете.
В моем контроллере я просто делаю следующее:
if (![self.canteen hasRestaurants]) {
[self.canteen loadRestaurantsWithCallback:^{
[self.tableView reloadData];
}];
}
Это работает как шарм. Что вы думаете об этом решении?
Обновление : 24 июня 2011 г. 16:30 CET
Существует четвертое решение этой проблемы, и, вероятно, это правильный путь, даже если он включает в себя больше кода, чем подход GCD. Вот что я придумал:
Используйте NSURLConnection
для асинхронной загрузки.
Пусть ваша модель ответит на обратные вызовы, отправленные экземпляром NSURLConnection
.
Использование Кодирование значения ключа и Наблюдение значения ключа .
В вашем контроллере вы просто должны сделать следующее:
[self.model addObserver:self forKeyPath:@"method-name" options:0 context:NULL];
и
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
[self.tableView reloadData];
}