Данная статья является вольным переводом из официальной документации. В случае каких то неясностей прошу обратиться к первоисточнику: App Programming Guide for iOS

Когда пользователь не активно пользуется вашим приложением, система перемещает его в состояние background. Для многих приложений, это состояние просто короткая остановка на пути к полному выключению suspended. Приложения в состоянии suspended сохраняют зарят батарей и позволяют системе освободить важные для системы ресурсы для новый приложений требуемых внимания пользователя.

Большинство приложений может быть перенесено в “растянутое” состояние достаточно просто, но есть так же законные основания для продолжения работы в фоновом режиме. Туристическое приложение, возможно, захочет отслеживать позицию человека в течении долгого времени, так что оно может отображать курс накладывая его поверх туристической карты. Музыкальное приложение может нужнаться в продолжении проигрывания музыки даже при блокировке экрана. Другие приложения могут хотеть скачивать данные в фоне, чтобы минимизировать задержку в отображении данных пользователю. Когда вам понадобиться держать ваше приложение запущенным в фоне, iOS поможет вам эффективно сделать это и без “съедания” ресурсов системы и аккумулятора. Методы предлагаемые iOS деляться на три категории:

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

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

Запуск задач известной длины

Приложения перемещенные в фон, как ожидается, должны выйти из этого состояния как можно быстрее, так как они могут быть остановлены системой. Если ваше приложение находиться в середине задачи и вам нужно немного дополнительного времени для ее завершения, то вы можете вызвать методы beginBackgroundTaskWithName:expirationHandler: или beginBackgroundTaskWithExpirationHandler:](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIApplication_Class/index.html#//apple_ref/occ/instm/UIApplication/beginBackgroundTaskWithExpirationHandler:) объекта UIApplication запросив дополнительное время. Вызов любого из этих методов отстрочит ненадолго закрытие вашего приложения, дав немного дополнительного времени для завершения работы. После завершения этой работы ваше приложение должно вызвать метод endBackgroundTask: дав системе понять, что задача завершена и приложение может быть закрыто.

Каждый вызов методов beginBackgroundTaskWithName:expirationHandler: или beginBackgroundTaskWithExpirationHandler: генерирует уникальный токен для каждой задачи. Когда приложение завершит задачу, он должен вызвать метод endBackgroundTask: с соответствующим токеном дав системе понять, что именно эта задача была завершена. Отказ от вызова этого метода для фоновой задачи приведет к прекращению работы вашего приложения. Если вы предоставили обработчик когда запускали задачу, система вызовет этот обработчик дав вам последний шанс на то, чтобы закончить задачу и избежать выключения.

У вас нет необходимости ждать пока приложение будет перенесено в состояние фоновой работы для обозначения фоновых задач. Более полезным методом разработки является вызов beginBackgroundTaskWithName:expirationHandler:  или  beginBackgroundTaskWithExpirationHandler: до запуска задачи и вызов метода endBackgroundTask: после завершения. Вы можете следить за этим паттерном пока ваше приложение работает на переднем плане.

Листинг 3-1 показывает как можно запустить долго-работающую задачу когда ваше приложение перемещено в фон. В этом примере, происходит запрос к фоновой задаче включая обработчик в случае если задача выполняется слишком долго. Сама задача ставится в очереднь для асинхронного запуска, так что метод applicationDidEnterBackground: может вернутся нормально. Используйте упрощающие блоки кода необходимые для поддержания ссылок на любые важные перменные, таких как идентификатор фоновой задачи. bgTask это переменная класса хранящая ссылку на данную фоновую задачу и инициализируемая в этом методе.

Листинг 3-1 Запуск фоновой задачи в момент выхода

- (void)applicationDidEnterBackground:(UIApplication *)application
{
  bgTask = [application beginBackgroundTaskWithName:@"MyTask" expirationHandler:^{
      // Clean up any unfinished task business by marking where you
      // stopped or ending the task outright.
      [application endBackgroundTask:bgTask];
      bgTask = UIBackgroundTaskInvalid;
  }];
  // Start the long-running task and return immediately.
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
      // Do the work associated with the task, preferably in chunks.
      [application endBackgroundTask:bgTask];
      bgTask = UIBackgroundTaskInvalid;
  });
}

Обратите внимание: Всегда предоставляйте перехватчик завершения во время запуска задачи, но если вы хотите знать как много времени займет ваша задача от запуск, возьмите значение поля backgroundTimeRemaining из UIApplication.

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

Загрузка данных в фоне

Когда загружаются данные, приложения должны использовать объект NSURLSession для запуска загрузки, так система сможет взять управление процессом загрузки на себя в случае если приложение было выключено. Когда вы настраиваете этот объект для передачи в фоне, система управляет этой передачей в отдельном процессе и оповещает о статусе работы вашему приложениею в обычном случае. Если ваше приложение было выключено, пока продолжалась передача, система продолжит передачу в фоне и запустить ваше приложение (если это уместно) когда передача завершится или одна или более задач требует внимания вашего приложения.

Для поддержки фоновых передач, вы должны настроить ваш объект. Настраивая сессию, вы должны сначала создать объект NSURLSessionConfiguration и выбрать несколько настроек. Вы отправляете конфигурацию в объект в момент инициализации объекта NSURLSession.

Процесс создания объекта конфигурации, который поддерживает фоновые загрузки выглядит следующим образом:

  1. Создание объекта конфигурации используя метод backgroundSessionConfigurationWithIdentifier: объекта NSURLSessionConfiguration.
  2. Выбрать значение sessionSendsLaunchEvents объекта конфигурации в YES.
  3. Если ваше приложение начинает передачу на переднем плане, советуется выбрать значение discretionary в YES.
  4. Настройте любые другие свойства объекта конфигурации в зависимости от обстоятельств.
  5. Используйте объект конфигурации чтобы создать объект NSURLSession.

Единожды сконфигурированный, ваш объект NSURLSession сможет использоваться для задач выгрузки и скачивания в системе в нужное время. Если задачи выполнены пока приложение все еще запущено (или на переднем плане или в фоне), объект сессии будет уведомлен в обычном порядке. Если задачи не завершены и система выключива ваше приложение, система автоматический продолжит управлять задачей в фоне. Если пользователь зщавершил задачу, система завершит люую выполняемую задачу.

Когда все задачи происходящие в фоновой сесси были завершены, система перезапускает выключеное приложение (предпологается, что свойство sessionSendsLaunchEvents установлено в YES и пользователь не завершил работу приложения самостоятельно) и вызывает приложение с помощью метода application:handleEventsForBackgroundURLSession:completionHandler:. (Система может также перезапустить приложение для выполнения задач аутентификкации и других событий, связанные с вниманием вашего приложения.) В вашем приложении реализация этого метода, происходит с созданием нового NSURLSessionConfiguration и NSURLSession объекта с похожей конфигурацией что и ранее. Система переподключает ваши новый объект сессии на предыдущие задачи и оповещает об их статусе в новый объект сессии.

Реализация долго-работающих задач

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

  • Приложения играющие аудио данные пользователю в фоне, такие как приложения музыкальных плееров
  • Приложения записывающие звук пока находяться в фоне
  • Приложения информирующие пользователя о его локации все время, такие как приложения навигации
  • Приложения поддерживающих VoIP
  • Приложения нуждающиеся в загрзки новых данных регулярно
  • Приложения принимающие постоянное обновления от внешних аксессуаров

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

Объявление ваших фоновых задач

Поддержка некоторых типов фоновых работ должна быть объявлена в вашим приложении. В Xcode 5 и позних версиях, вы объявляете о поддержке фоновой работы во вкладке Capabilities в насройках проекта. Включание опции фонового режима добавляеет ключ UIBackgroundModes в вашем файле Info.plist. Выберете один или более чекбоксов добавив необходимые опции фоновой работы. Таблица 3-1 описывает фоновые режимы которые вы можете выбрать в Xcode.

Таблица 3-1 Фоновые режимы приложения.

Xcode фоновой режим

UIBackgroundModes значение

Описание

Аудио и AirPlay

audio

Приложение играет аудио данные пользователя или записывает данные в фоне. (Эти данные включают потокове аудио или видео данные используя AirPlay.)

Пользователь должен разрешить приложению использовать пикрафон во время первого использвания; для большей информации читайте Supporting User Privacy.

Обновление локации

location

Приложение информирует пользователя о его положении пока находиться в фоне

IP-телефония

voip

Приложение позволяет пользователю совершать звонки через интернет.

Загрзки Newsstand

newsstand-content

Приложение является приложением Newsstand, которое производить загрузки и обработку журналов или газет в фоне.

Общение с внешними аксессуарами

external-accessory

Приложение работает с аппаратными аксессуарами необходимых в обновлении по расписанию через фреймворк External Accessor.

Использование Bluetooth LE аксессуаров

bluetooth-central

Приложение работает с Bluetooth аксессуарами необходимые в обновлении по расписанию через фреймворк Core Bluetooth.

Дейтвия с Bluetooth LE аксессуарами

bluetooth-peripheral

Приложние поддерживает общение через Bluetooth в режиме переферии через фреймворк Core Bluetooth.

Этот режим используется для запросов пользовательской аутонтификации; для большей информации читайте Supporting User Privacy.

Фоновые приемы

fetch

Приложение регулярно загружает и обрабатывает маленькие размеры информации из интернета.

Удаленные уведомления

remote-notification

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