Могу ли я использовать непрерывный фоновый поток для обновления пользовательского интерфейса iPhone без использования NSTimer? - PullRequest
0 голосов
/ 31 июля 2010

Допустим, что если я прочитал с www.example.com/number, я получу случайное число.В моем приложении для iPhone я хочу иметь возможность непрерывно считывать с этого адреса и отображать новый номер на экране после завершения каждого запроса.Давайте также предположим, что я хочу, чтобы этот процесс запустился, как только загрузится представление.Наконец, в качестве дополнительного примечания я использую ASIHTTPRequest для упрощения веб-запросов.

Подход 1. В моем методе viewDidLoad я мог синхронно считывать URL-адрес в цикле (выполнение не будет продолжено, пока я не получу ответ от HTTP-запроса).Плюсы: запросы являются последовательными, и у меня есть полный контроль, чтобы ответить на каждый.Минусы: пользовательский интерфейс никогда не обновляется, потому что я никогда не выхожу из функции и не возвращаю управление циклу времени выполнения.Понятно, что это не очень хорошее решение.

Подход 2: В моем методе viewDidLoad я создаю таймер, который вызывает функцию fetchURL раз в секунду.Плюсы: каждый запрос находится в отдельном потоке, а пользовательский интерфейс обновляется после завершения каждого запроса.Минусы: запросы находятся в отдельных потоках, и не могут быть хорошо контролируются.Например, если по первому запросу есть тайм-аут соединения, я хочу иметь возможность отображать всплывающее окно с ошибкой, и больше никаких запросов не происходит, пока настройки не будут изменены.Однако при таком подходе, если тайм-аут занимает 3 секунды, за это время уже будут запущены два дополнительных запроса.Если я просто замедляю таймер, тогда данные приходят слишком медленно, когда соединение работает хорошо.

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

Подход 3: Я подумал об использовании таймера, который срабатывает быстрее (скажем, каждые 0,25 секунды), но функция таймера проверяет флаг, чтобы увидеть, что делать дальше.Таким образом, если предыдущий запрос завершен, он отправляет новый запрос (если не было ошибки).В противном случае, если предыдущий запрос не завершен, функция таймера возвращается без отправки нового запроса.При более быстром срабатывании этого таймера вы получите лучшее время отклика, но флаг позволит мне получить необходимую синхронизацию.

Кажется, что подход 3 будет делать то, что я хочу, но это также кажется немного вынужденным.У кого-нибудь есть предложение для лучшего подхода к этому, или что-то вроде подхода 3 является лучшим способом сделать это?

Ответы [ 3 ]

2 голосов
/ 31 июля 2010

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

В viewDidLoad вызовите блок асинхронно (используя dispatch_async), который выполняет следующие действия:

  1. Загрузка данных с помощью синхронного вызова иобрабатывать таймауты в случае неудачи.
  2. В случае успеха информировать главный поток об обновлении интерфейса.
  3. Поставить в очередь новый блок для запуска после задержки, которая делает то же самое (используя dispatch_after).

Чтобы перезвонить основному потоку из другого потока, я могу подумать о следующих методах:

  1. Если вы хотите обновить пользовательское представление, вы можете установить setNeedsDisplay из вашего блока
  2. В противном случае вы можете поставить блок в очередь в так называемую «главную очередь», то есть очередь, выполняющуюся в главном потоке.Вы получите эту очередь, позвонив dispatch_get_main_queue.а затем обрабатывать его как любую другую очередь (например, вы можете добавить свой блок, вызвав dispatch_async).
  3. Если вы не хотите использовать блоки, вы можете использовать NSObject 's performSelectorOnMainThread:withObject:waitUntilDone:method.

См. GCD Reference для получения более подробной информации.

Тем не менее, вы никогда не должны выполнять небольшие запросы так часто (если только для конкретных задач, таких как загрузка игры)данные или что-то).Это позволит значительно сократить срок службы батареи, не давая антенне спать.

1 голос
/ 31 июля 2010

Я считаю, что NSOperation - это то, что вам нужно.Используйте решение номер 1 выше, но поместите код в основной метод вашей NSOperation.Примерно так:

.h файл

@interface MyRandomNumberFetcher : NSOperation {

}

@end

.m файл

@implementation MyRandomNumberFetcher

- (void) main {
      // This is where you start the web service calls.
}

@end

Я бы также рекомендовал добавить ссылку на контроллер UI, чтобы вашКласс очереди операций может перезвонить, когда это уместно.

0 голосов
/ 31 июля 2010

Вот еще одно предложение. Создайте NSOperationQueue, который будет выполнять ваши запросы в другом потоке. Если вы обнаружите, что вам нужно обновить вызов интерфейса пользовательского интерфейса executeSelectorOnMainThread. Когда запрос завершится, создайте другой запрос и добавьте его в очередь. Установите очередь для запуска только одного действия за раз.

Таким образом, у вас никогда не будет двух запросов одновременно.

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