Подтвердить что ты не робот

Asynchronous vs Synchronous vs Threading в приложении для iPhone

Я нахожусь в стадии разработки для приложения, которое будет использовать веб-службу REST и, как правило, имеет дилемму в отношении использования асинхронных и синхронных потоков. Вот сценарий.

Скажем, у вас есть три варианта, которые можно развернуть, каждый из которых имеет свой собственный ресурс на основе REST. Я могу либо лениво загружать каждый из них синхронным запросом, но блокирует пользовательский интерфейс и не позволяет пользователю удалять обратную навигационную кнопку во время получения данных. Этот случай применяется практически везде, кроме случаев, когда для вашего приложения требуется экран входа в систему. Я не вижу никакой причины использовать синхронные HTTP-запросы по сравнению с асинхронными из-за этой причины. Единственный раз, когда имеет смысл это сделать, чтобы рабочий поток выполнял ваш синхронный запрос и уведомлял основной поток, когда запрос выполнен. Это предотвратит блокировку. Тогда возникает вопрос: скамейка, маркирующая ваш код, и вид, у которого больше накладных расходов, потоковый синхронный запрос или асинхронный запрос.

Проблема с асинхронными запросами заключается в том, что вам нужно либо настроить интеллектуальную систему уведомлений, либо делегировать систему, поскольку у вас может быть несколько запросов на несколько ресурсов, происходящих в любой момент времени. Другая проблема с ними заключается в том, что если у меня есть класс, скажем, singleton, который обрабатывает все мои данные, я не могу использовать асинхронные запросы в методе getter. Значит, следующее не будет идти:

 - (NSArray *)users {
     if(users == nil)
        users = do_async_request // NO GOOD

     return users;
 }

тогда как следующее:

 - (NSArray *)users {
    if(users == nil)
      users == do_sync_request // OK.

    return users;
 }

У вас также может быть приоритет. То, что я подразумеваю под приоритетом, - если вы посмотрите приложение Apple Mail на iPhone, вы заметите, что они сначала высасывают все дерево POP/IMAP, прежде чем делать второй запрос на получение первых двух строк (по умолчанию) вашего сообщения.

Я полагаю, что мой вопрос для вас - эксперты. Когда вы используете асинхронные, синхронные, потоки - и когда вы используете либо асинхронную/синхронизацию в потоке? Какую систему делегаций вы настроили, чтобы знать, что делать, когда асинхронный запрос завершается? Вы оцениваете приоритеты своих асинхронных запросов?

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

4b9b3361

Ответ 1

Я не думаю, что есть "правильный" ответ. Кажется, что вы понимаете компромиссы, и вам просто нужно сделать свой дизайн вокруг них.

Несколько лишних случайных точек: иногда ваше приложение заставляет особый подход. Например, многие из удобных (то есть синхронных) методов не позволят аутентификацию. Для меня это означало, что мое решение было принято.

Для Yummy Я не использовал потоки. Я сделал все свои сетевые вызовы асинхронными, и я использовал парсер XML по умолчанию (который работает с использованием обратных вызовов). Поскольку все события управляются и каждая единица мала, это позволяет графическому интерфейсу быть довольно жидким, не имея сложности с потоком.

Я использую конечный автомат, чтобы понять, почему я получаю конкретный ответ, и очередь, так что мне нужно только одну операцию "в полете" в любой момент времени. Для большинства запросов существует четкий порядок, поэтому мне не нужна система приоритета.

Сетевой код является самым сложным в моем приложении, и потребовалось много времени, чтобы работать гораздо менее надежно!

Ответ 2

Я не дисконтирую асинхронные вызовы делегатов, но обычно я использую класс рабочих потоков с синхронными запросами. В конечном итоге мне стало проще иметь хорошо определенный API с резьбой, а не заполнять ваш контроллер кодом, управляющим состоянием между асинхронными методами. Вы могли бы даже сделать асинхронным в своем рабочем потоке, хотя обычно проще использовать синхронные методы, если они не поддерживают функцию, которую вам нужно использовать. Конечно, все это зависит от обстоятельств, я могу думать о многих ситуациях, когда просто использование асинхронных методов было бы лучшим путем.

Определенно рассмотрите NSOperationQueue, если вы идете по этому маршруту; он значительно упрощает создание нескольких рабочих потоков, а также поддерживает приоритеты и зависимости между операциями. Прямо сейчас есть проблемы с ним на 10,5, но я не слышал о каких-либо проблемах на iPhone.

Ответ 4

Я лично смотрю, что делается, я буду использовать запрос asyc для обеспечения того, чтобы пользовательский интерфейс не блокировался, однако я МОГУ во время этого запроса отключить пользовательский интерфейс моего приложения.

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

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

Ответ 5

Я бы рекомендовал асинхронный путь, не вопрос. Затем загрузите информацию только при необходимости и используйте систему делегатов, чтобы предоставить эту информацию правильному объекту.

Вы не хотите блокировать пользовательский интерфейс. Когда-либо. А загрузка информации асинхронно позволяет вам лучше контролировать, что происходит, поэтому при необходимости вы можете вызвать сообщение об ошибке.

Ответ 6

Просто мысль: если вы хотите использовать платформу Unit Testing для iPhone, вы можете захотеть иметь синхронную функциональность, поскольку это могло бы облегчить запись тестов.

Однако некоторые из ваших API могут работать не синхронно, поэтому вам нужно включить их в задачи синхронизации. Если код, который выполняет модульное тестирование, запускается в своем потоке, вы можете написать оболочку, которая будет ждать завершения задачи async.

Чтобы добиться этого, вы должны использовать семафор: ваша функция-обертка запускает операцию async, а затем использует семафор, чтобы блокировать себя (т.е. ставит себя в спящий режим). Обратный вызов, который сигнализирует о завершении асинхронного события, освобождает семафор, так что поток спящего обертки может продолжать и возвращаться.

Ответ 7

Я бы использовал dispatch_async с синхронным. Таким образом, у вас есть преимущество без делегатов /NSNotifications и он не блокирует

- (NSArray *)users {
    if(users == nil) {
        users = do_sync_request();
    }

    return users;
}

// now when calling the users method, do this

- (NSArray *)getUsers {
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
           NSArray *users = [self users];
           dispatch_sync(dispatch_get_main_queue(), ^{
                 return users;
           }
     }
}

Ответ 8

Почему вы не можете использовать асинхронный запрос следующим образом:

- (NSArray *)users {
     if(users == nil && !didLaunchRequestAlready )
        users = do_async_request // Looks good to me
     return users;
 }

Асинхронный - это абсолютно единственный вариант - единственный реальный вопрос - если вы хотите начать использовать отдельные потоки или хотите просто использовать асинхронные вызовы. Начните там и посмотрите на управление потоками, если вам действительно нужно.