Удобные методы AFHTTPSessionManager (GET, POST, PUT и т. д.) и фоновые передачи

Я создал приложение на основе AFHTTPSessionManager AFNetworking 2.0 и его удобных методов HTTP. Теперь мне нужно убедиться, что все эти сетевые функции могут работать в фоновом режиме, и я весьма обеспокоен.

Читая документацию Apple, я вижу, что задачи данных не поддерживаются для фоновых сеансов. Кратко взглянув на реализацию GET, POST, PUT и др. в AFHTTPSessionManager, он, кажется, использует NSURLSessionDataTask по всем направлениям.

Есть ли что-то, что я упускаю, или мне нужно что-то переделать и переделать?

В случае, если я прав (и я подозреваю, что прав), и что этот путь кода не позволит мне выполнять фоновую загрузку и загрузку, есть ли какая-либо причина, по которой я не могу обернуть другие методы AFURLSessionManager, которые используют задачи, не связанные с данными, в так же, как текущие методы HTTP обертывают "dataTaskWithRequest:completionHandler"? Например, для POST я мог бы использовать «uploadTaskWithRequest: fromData: progress: completionHandler»?

Я спрашиваю, поскольку мне интересно, является ли это жизнеспособным маршрутом, почему разработчики AFNetworking не использовали его, чтобы удобные методы AFHTTPSessionManager позволяли выполнять фоновые передачи.


person Darren Black    schedule 12.02.2015    source источник


Ответы (1)


AFNetworking позволяет выполнять фоновые запросы (однако будьте осторожны, чтобы не использовать какие-либо блоки завершения для конкретных задач, и убедитесь, что вы реализуете соответствующие методы делегата приложения; см. AFNetworking 2.0 и фоновые передачи). Вероятно, вы также можете использовать requestWithMethod из AFHTTPRequestSerializer, чтобы упростить процесс создания запроса (хотя, IIRC, вы не можете использовать HTTPBody запроса с запросами на фоновую загрузку, поэтому вам, возможно, придется сохранить тело запроса в файл и затем отправьте запрос на фоновую загрузку, используя этот файл).

Но вы абсолютно правы в том, что вы не можете использовать методы AFHTTPSessionManager для запуска NSURLSessionDataTask задач при использовании фонового сеанса. Что касается того, почему они реализовали это таким образом, этот вопрос лучше подходит для их форума.

person Rob    schedule 12.02.2015
comment
Привет Роб. Я читал этот пост несколько раз и надеялся, что вы ответите на него :) Это может быть немного не по теме ОП, но мне любопытен идентификатор фонового сеанса. В нынешнем виде у меня есть множество операций и типов операций в моем подклассе AFHTTPSessionManager. В любой момент может выполняться любая комбинация этих операций, и то, что нужно сделать по завершении этих операций, может быть разным — иногда обновление модели CoreData, иногда ничего. Учитывая, что у меня есть только 1 идентификатор сеанса для каждого менеджера, я полагаю, мне нужно создать один менеджер для каждого оператора для такого контроля? - person Darren Black; 12.02.2015
comment
Либо так, либо вы должны поддерживать некоторую перекрестную ссылку (и убедиться, что она поддерживается в постоянном хранилище) между запросами и типом действия, которое вы хотите выполнить в методах делегата завершения. Или, возможно, вы сможете определить правильное действие на основе originalRequest.URL задачи. Есть куча способов справиться с этим... - person Rob; 12.02.2015
comment
Да... дело в том, что это несколько сложно. В настоящее время приложение в значительной степени зависит от блоков успеха и отказа AFHTTPSessionManager с несколькими уровнями функциональности, отражающими его. Таким образом, это не просто тип действия, который необходим при завершении, это действие, указанное вызывающим уровнем. Итак, что я собираюсь сделать здесь, так это создать интерфейс, который имитирует то, что предоставляет AFHTTPSessionManager, но не имеет ограничений, связанных с неработоспособностью в фоновом режиме. Это вообще выполнимо? Я эффективно просматриваю блоки внутри блоков внутри блоков по завершении задачи... - person Darren Black; 12.02.2015
comment
Вам либо нужно придумать дизайн, который использует только блоки завершения на уровне сеанса, либо вам нужно по-другому обрабатывать фоновые запросы (например, вместо фонового NSURLSessionConfiguration использовать стандартный сеанс, но отдохнуть несколько минут, чтобы завершить запросы с beginBackgroundTask, что-то это работает только в том случае, если выполнение запросов не занимает более нескольких минут). - person Rob; 12.02.2015
comment
Конечно. Я предполагаю, что меня сбивает с толку то, что может быть даже блок завершения после завершения и возрождения приложения. Если этот блок выполняет операцию над другим объектом (например, вызывающим), я не понимаю, как это может работать, когда приложение возрождается... Думаю, мне нужно будет запустить некоторые тесты, если вы этого не знаете? Я предполагаю, что задача всегда возвращается без изменений (с полным запросом + ответом и т. д.). Эту часть мне несколько легче проглотить. - person Darren Black; 12.02.2015
comment
Нет, ваша интуиция здесь абсолютно верна. Должно быть, я был неясен в том другом посте. Блоки не сохраняются. Вот почему вы не можете полагаться на какие-либо блоки для конкретных задач, потому что все они потеряны. Итак, что я сделал, так это повторно создал блоки уровня сеанса при следующем запуске приложения, тем самым ограничив меня каким-то простодушным обработчиком, который действует исключительно на основе задачи (например, захватывает URL-адрес и принимает решения). Но вы правы в том, что все старые блоки, переменные и прочее давно ушли в прошлое. - person Rob; 12.02.2015
comment
Хорошо... тут мне кое-что осталось неясным. Согласно документации Apple, единственный метод, который я могу ожидать, когда приложение было завершено во время фоновой загрузки, — это handleEventsForBackgroundURLSession, и он вызывается, когда все задачи для сеанса выполнены. Содержит ли AFNetworking некоторую магию, которая вызовет блок, который вы установили в setDownloadTaskDidFinishDownloadingBlock? Или я полностью теряю детализацию для каждой задачи, когда приложение завершается системой? - person Darren Black; 16.02.2015
comment
Или handleEventsForBackgroundURLSession, возможно, является вызовом, который говорит вам настроить ваши сеансы, чтобы вы могли обрабатывать некоторые обратные вызовы для конкретных задач, которые неизбежны? Это кажется мне единственным жизнеспособным маршрутом на самом деле, так как весь этот сеанс закончен... что-то без подробностей было бы в значительной степени бесполезным. - person Darren Black; 16.02.2015
comment
Когда сеанс завершен, ваше приложение пробуждается и вызывается handleEventsForBackgroundURLSession, в котором мы повторно создаем фоновый сеанс и сохраняем файл completionHandler. Теперь NSURLSession будет вызывать методы делегата завершения задачи сеанса (в быстрой последовательности, если у вас было несколько завершенных фоновых задач), что означает, что downloadTaskDidFinishDownloadingBlock, который мы только что воссоздали, будет вызываться для каждой фоновой задачи. Наконец, вызывается URLSessionDidFinishEventsForBackgroundURLSession, и вызывается блок, который мы определили для вызова сохраненного completionHandler. - person Rob; 16.02.2015
comment
Или, возможно, handleEventsForBackgroundURLSession является вызовом, который говорит вам настроить ваши сеансы, чтобы вы могли обрабатывать некоторые обратные вызовы для конкретных задач, которые неизбежны? Итак, да, это именно то, что происходит: наш процесс вызова нашего синглтона для сохранения completionHandler, что более важно, создает экземпляр сеанса, который, в свою очередь, позволяет автоматически вызывать методы завершения фоновой задачи. - person Rob; 16.02.2015
comment
Глядя на доступные обработчики завершения на уровне сеанса, кажется, что метод setDownloadTaskDidFinishDownloadingBlock не допускает ошибок. Так что, если загрузка не удалась, вы не можете отреагировать? В этой ситуации нужно ли использовать setTaskDidCompleteBlock для реагирования на ошибки загрузки? - person Darren Black; 24.02.2015
comment
да. И помните, есть два типа ошибок. Есть основные проблемы с подключением, которыми занимается setTaskDidCompleteBlock. Но такие ошибки, как 404 - not found, таким образом не сообщаются. Вы также должны проверить statusCode в setDownloadTaskDidFinishDownloadingBlock (например, проверить, является ли [downloadTask.response isKindOfClass:[NSHTTPURLResponse class]], и если да, посмотреть, равно ли [(NSHTTPURLResponse *)downloadTask.response statusCode] 200 или нет. - person Rob; 24.02.2015
comment
Спасибо... до сих пор вы здорово помогали. Я получаю какое-то странное поведение при обработке пробуждения от завершения (я имитирую это, убивая приложение из Xcode после того, как некоторые передачи инициированы)... и мне интересно значение обработчика завершения, предоставленного в setDidFinishEventsForBackgroundURLSessionBlock:. Изучив источник, кажется, что AFN вызывает это, как только получает соответствующий обратный вызов от системы. Но какая у этого семантика? Означает ли это, что система может снова убить приложение? - person Darren Black; 25.02.2015
comment
... Я использую NSNotifications для запуска обработки завершенных передач/задач в другом месте системы, поскольку я не хочу напрямую связывать «бизнес-логику» приложения с сетевыми операциями нижнего уровня. - person Darren Black; 25.02.2015
comment
В документации говорится: «Вызов этого обработчика завершения позволяет системе узнать, что пользовательский интерфейс вашего приложения обновлен и можно сделать новый снимок». Лично я думаю, что здесь замешано что-то гораздо более глубокое: вызов этого завершенияHandler — это ваш способ сообщить ОС, что обработка всех этих ответов завершена и что поэтому приложение может безопасно остановить фоновое выполнение. Что касается вашего странного поведения, я бы посоветовал вам опубликовать свой собственный вопрос, точно иллюстрирующий, что происходит. Но вы действительно должны перестать публиковать дополнительные вопросы здесь, в комментариях. - person Rob; 25.02.2015