Статьи

iOS 7 SDK: улучшения многозадачности

Из этого туториала вы узнаете все о последних усовершенствованиях многозадачности, предоставляемых iOS 7 SDK. В частности, вы узнаете об интерфейсах «Фоновая выборка», «Удаленные уведомления» и «Служба фоновой передачи». Читай дальше!


С iOS 7 Apple сделала три новых API многозадачности доступными для разработчиков:

  • Background Fetch
  • Удаленные уведомления
  • Фоновая служба передачи

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


Чтобы упростить понимание API Background Fetch , представьте, что вы хотите создать новостное приложение. Гипотетически мы предполагаем, что контент этого приложения предоставляется из Интернета, и одна из важных функций — получать обновления каждый раз, когда пользователь запускает приложение.

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

На iOS 7 все резко изменилось! Благодаря API Background Fetch наше гипотетическое приложение может фактически пассивно загружать новый контент, оставаясь при этом в фоновом режиме. iOS 7 разбудит приложение, предоставит время фонового выполнения, и, когда приложение завершит обновление, оно снова перейдет в спящий режим. Конечно, пользователи не уведомляются, когда это происходит. Они просто находят новый контент готовым к запуску после запуска приложения.

Процесс обновления может происходить через предварительно заданные интервалы, установленные программистом, или через интервалы, заданные операционной системой. Если вы устанавливаете пользовательские интервалы, Apple рекомендует устанавливать их разумно и не очень часто извлекать данные в фоновом режиме. Это приведет к разрядке батареи и потере системных ресурсов. Если вы просто позволите операционной системе что-то делать, iOS 7 сделает прогнозы использования. Это делается путем наблюдения за тем, как часто приложение запускается и в какое время. Затем он ожидает такого поведения, выходя в сеть и выбирая контент, прежде чем предсказывает, что пользователь захочет его. Например, если пользователь нашего гипотетического новостного приложения запускает приложение каждый день, iOS наблюдает за этим и решает, что приложение должно получать контент где-то днем ​​и до обычного времени запуска. Очень круто!

Процесс извлечения, описанный выше, включает в себя три этапа:

  1. Чтобы включить возможность фоновой выборки
  2. Чтобы установить минимальный интервал времени
  3. Для реализации нового application:performFetchWithCompletionHandler: метода делегата application:performFetchWithCompletionHandler:

Давайте рассмотрим вещи более подробно.

Как я только что упомянул, первым шагом во всем процессе является включение возможности фоновой выборки для приложения в Xcode 5. Это можно сделать двумя способами. Первый способ — использовать файл .plist , в который необходимо добавить ключ « Required background modes со значением fetch , например:

gt7_1_plist_fetch

Следующие шаги являются альтернативным подходом:

  • Нажмите на название проекта в левом верхнем углу в Xcode
  • Нажмите на вкладку «Возможности» в среднем окне.
  • Под опцией Фоновые режимы установите флажок Фоновая выборка
gt7_2_capabilities_fetch

По умолчанию начальное значение интервала выборки установлено в режим UIApplicationBackgroundFetchIntervalNever , что означает, что фоновая выборка никогда не будет выполняться. Если это значение не изменяется, фоновая выборка не будет работать, даже если она включена одним из двух способов, описанных выше. Для этого вам нужно перейти в application:didFinishLaunchingWithOptions: и установить минимальное значение интервала выборки следующим образом:

1
2
3
4
5
6
— (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
     
    return YES;
}

UIApplicationBackgroundFetchIntervalMinimum — это минимальное значение интервала, разрешенное и управляемое системой. Конечно, вы можете установить пользовательский интервал времени, просто NSTimeInterval метода выше значение NSTimeInterval . Однако, если в этом нет необходимости, обычно лучше позволить iOS решить, когда оно должно позволить приложению работать в фоновом режиме и получать новый контент. Если вы устанавливаете минимум, важно понимать, что UIApplicationBackgroundFetchIntervalMinimum не совсем определяет время. Они больше похожи на предложения. iOS попытается следовать графику, если сможет, но, в зависимости от доступных системных ресурсов, выборка может происходить чаще или реже, чем хотелось бы.

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

  1. UIBackgroundFetchResultNewData : если при UIBackgroundFetchResultNewData были найдены новые данные
  2. UIBackgroundFetchResultNoData : если новые данные не найдены
  3. UIBackgroundFetchResultFailed : если во время процесса выборки произошла ошибка

Давайте посмотрим на это в действии:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
-(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
     
    // Call or write any code necessary to get new data, process it and update the UI.
     
    // The logic for informing iOS about the fetch results in plain language:
    if (/** NEW DATA EXISTS AND WAS SUCCESSFULLY PROCESSED **/) {
        completionHandler(UIBackgroundFetchResultNewData);
    }
     
    if (/** NO NEW DATA EXISTS **/) {
        completionHandler(UIBackgroundFetchResultNoData);
    }
     
    if (/** ANY ERROR OCCURS **/) {
        completionHandler(UIBackgroundFetchResultFailed);
    }
}

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

Есть еще несколько фактов, которые вы должны знать. Во-первых, когда приложение запускается в фоновом режиме, у него есть около тридцати секунд для выполнения всех необходимых задач и вызова обработчика завершения. Если этот срок превышен, приложение снова будет приостановлено. Для приложений, которым требуется более 30 секунд (возможно, из-за загрузки мультимедиа), следует запланировать фоновую выборку с помощью API службы фоновой передачи. Мы обсудим этот вариант позже.

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

Первый подход состоит из следующих шагов:

  • Запустите приложение как обычно на Симуляторе
  • Пока приложение работает, вернитесь в Xcode
  • Нажмите меню « Отладка»> «Симулировать фоновую выборку».

Этот способ полезен, чтобы попробовать API во время работы приложения. Второй способ более сложный, но он позволяет вам тестировать приложение, пока оно остается в фоновом режиме. Чтобы попробовать это, выполните следующие действия:

  • Перейдите к списку « Схемы» и нажмите « Управление схемами» .
    gt7_3_manage_schemes
  • Убедитесь, что выбрана текущая схема, а затем продублируйте ее, нажав на кнопку «шестеренка» в нижней части окна и выбрав « Дублировать» .
    gt7_4_duplicate_scheme
  • Установите имя для дубликата, если хотите.
  • Выберите опцию « Выполнить» на левой панели, затем щелкните вкладку « Параметры ».
  • Установите флажок Запуск из-за события фоновой выборки и дважды нажмите кнопку ОК .
    gt7_5_scheme2
  • Запустите приложение, используя дублированную схему.

Фоновая выборка предназначена для некритических обновлений приложения, так как время, когда оно происходит, может отличаться. Для более важных обновлений см. Следующий раздел «Удаленные уведомления». Как правило, API фоновой выборки подходит для приложений, которые хотят беспрепятственно управлять контентом. Несколько примеров категорий приложений включают новости, социальные сети, погоду и обмен фотографиями.


Представьте, что мы создаем приложение как с письменными, так и с видеоуроками. Предположим, что пользователи могут загружать новые обучающие видеоролики 2-3 раза в месяц. Итак, как мы будем информировать наших пользователей о новых видео релизах? Мы не можем принять решение, которое использует API фоновой выборки или что-то подобное, так как это приведет как к пустой трате ресурсов устройства, так и к бессмысленным запросам к серверу. Мы также не можем знать, когда новый видео релиз готов. Поэтому нам нужно использовать Push-уведомления, поэтому каждый раз, когда появляется новый контент, мы можем сообщать об этом нашим пользователям, просто предупреждая их. Мы ожидаем, что наши пользователи впоследствии запустят приложение и загрузят новый контент. Проблема заключается в том, что этот подход заставляет пользователя ждать загрузки видео, и если контент достаточно большой, ему, возможно, придется долго ждать. Итак, как пользователи могут получить новый контент в своем приложении, когда этот контент доступен, но без ожидания?

Это где удаленные уведомления пригодятся. Удаленные уведомления на самом деле представляют собой автоматические push-уведомления , то есть push-уведомления, которые не информируют пользователей об их существовании. Когда приходит новое удаленное уведомление, система автоматически разбудит приложение, чтобы оно могло обработать уведомление. Затем приложение отвечает за запуск процесса загрузки нового контента. Когда загрузка заканчивается, пользователю отправляется локальное уведомление . Когда приложение запускается, новый контент ожидает пользователя.

Как и Background Fetch, удаленные уведомления направлены на устранение времени ожидания, с которым сталкиваются пользователи при загрузке нового контента или загрузке данных на сервер. Оба API работают в фоновом потоке, и пользователи получают уведомление после завершения задания. Тем не менее, удаленные уведомления подходят в тех случаях, когда контент либо редко обновляется, либо имеет иное значение для взаимодействия с пользователем.

Чтобы использовать удаленные уведомления в приложении, вам нужно сначала включить их. Вы можете сделать это либо с помощью файла * .plist, либо с помощью новой вкладки проекта Capabilities . Если вы хотите использовать файл * .plist, вам нужно добавить обязательный фоновый ключ со значением удаленного уведомления следующим образом:

gt7_6_plist_remote

Чтобы использовать вкладку «Возможности», выполните следующие действия:

  • Нажмите на название проекта в левом верхнем углу в Xcode
  • Нажмите на вкладку « Возможности » в среднем окне.
  • Под опцией Фоновые режимы установите флажок Удаленные уведомления
gt7_7_capabilities_remote

Следующим шагом является реализация application:didReceiveRemoteNotification:fetchCompletionHandler: метод делегата в файле AppDelegate. Этот вызывается, когда приходит новое уведомление. Используйте обработчик завершения, чтобы уведомить iOS о результате выборки данных:

1
2
3
4
5
6
-(void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler{
     
    // Call or write any code necessary to download new data.
     
    completionHandler(UIBackgroundFetchResultNewData);
}

Сделать уведомление молчать довольно легко. В полезные данные уведомлений нужно просто включить флаг code-available: 1 и опустить все оповещения или звуковые данные, которые будут уведомлять пользователя.

1
2
3
aps{
   content-available: 1
}

В общем, все, что действует при работе с Background Fetch, применимо и здесь. Например, у вас есть максимум 30 секунд, чтобы загрузить любой новый контент и уведомить систему описанным выше способом, прежде чем приложение снова перейдет в спящий режим. Если для загрузки нового контента требуется время, рассмотрите возможность использования API службы фоновой передачи .

Имейте в виду, что Apple контролирует скорость удаленной доставки уведомлений (автоматических push-уведомлений), отправляемых push-провайдером. Если скорость нормальная, то и обычные, и тихие уведомления доставляются сразу. Однако, когда молчаливые уведомления отправляются довольно часто, служба Apple Push сохраняет их для доставки позднее. Убедитесь, что вы отправляете любые удаленные уведомления с умом.


Еще одна замечательная особенность iOS 7 — это API Background Transfer Service . Традиционно получать или отправлять большие порции данных было непросто, в основном из-за ограничений времени выполнения и управления передаваемыми данными. Приложения должны были завершить большую часть процесса загрузки или выгрузки, пока они находились на переднем плане. Однако с iOS 7 все совершенно иначе. Приложения могут пользоваться большей свободой при выполнении фоновых задач. Прежде всего, с помощью службы фоновой передачи приложениям предоставляется столько времени, сколько им необходимо для завершения передачи. Находятся ли они на переднем плане или на заднем плане, не имеет значения. Временные ограничения больше не существуют, и теперь система отвечает за управление данными, которые загружаются или загружаются. Даже если приложение не запущено, iOS разбудит его для обработки ситуаций, когда необходимо принимать решения. Несколько примеров этого включают, когда загрузка файла завершается или когда на сервер должна быть предоставлена ​​дополнительная информация.

Служба фоновой передачи основана на классе NSURLSession , который только что был представлен в iOS 7. Этот класс отвечает за передачу данных через HTTP или HTTPS и предоставляет возможность для фоновых задач, связанных с сетью. Вся идея этого проста и основана на использовании сеансов , где один сеанс управляет всеми связанными задачами передачи данных. Доступны различные типы сессий, но мы заботимся о фоновых сессиях , и они всегда работают с отдельными потоками (процессами), созданными системой. Фоновые сеансы поддерживают задачи загрузки ( NSURLSessionDownloadTask ) и загрузки ( NSURLSesssionUploadTask ), которые добавляются в фоновые объекты NSURLSession .

Еще один заслуживающий внимания факт, связанный с фоновыми передачами, заключается в том, что перевод может быть дискреционным или недискреционным. Недискреционные передачи могут быть инициированы только тогда, когда приложение находится на переднем плане, но есть возможность установить дискреционное состояние в соответствии с потребностями приложения. Дискреционные передачи в основном предпочтительны, поскольку они позволяют операционной системе добиться более эффективного управления энергопотреблением на устройстве. Существует также одно ограничение, которое применяется к дискреционным передачам, а именно, что они должны выполняться только через сети WiFi. Фоновые передачи потоков всегда инициируются как дискреционные передачи.

Приложение метода делегата application:handleEventsForBackgroundURLSession:completionHandler: вызывается, когда фоновая передача завершается, чтобы завершенная задача могла быть обработана. Например, если новый контент был загружен, вы должны реализовать этот метод делегата для его постоянного хранения и обновления пользовательского интерфейса при необходимости. Этот метод также вызывается, когда из приложения требуются учетные данные для продолжения передачи. Как правило, в этом методе делегата вы применяете всю необходимую логику, требуемую вашим приложением, когда процесс загрузки или выгрузки завершен, и приложение существует в фоновом потоке. Конечно, вы используете обработчик завершения, чтобы система знала, когда вы закончите, чтобы она могла вернуть приложение в спящий режим.

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


Фоновая выборка, удаленные уведомления и API-интерфейсы службы фоновой передачи — это функции, которые разработчики хотели бы увидеть давно. К счастью, с выпуском iOS 7 Apple упростила обработку данных приложений. Начиная с iOS 7, контент приложений практически всегда может быть актуальным, но в конечном итоге каждый разработчик должен позаботиться об этом и использовать предоставленные инструменты! Удачной многозадачности, и спасибо за чтение!