Стратегии обработки изменений состояния приложения

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

Что сделать во время запуска

Когда Ваше приложение будет запущено (или в передний план или в фон), используйте своего делегата приложения application:willFinishLaunchingWithOptions: и application:didFinishLaunchingWithOptions: методы, чтобы сделать следующее:

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

Ваш application:willFinishLaunchingWithOptions: и application:didFinishLaunchingWithOptions: методы должны всегда быть максимально легкими для сокращения времени запуска приложения. Приложения, как ожидают, запустят, инициализируют себя и начнут обрабатывать события меньше чем через 5 секунд. Если приложение не заканчивает свой цикл запуска своевременно, система уничтожает его для того, чтобы быть безразличной. Таким образом любые задачи, которые могли бы замедлить Ваш запуск (такой как доступ к сети) должны быть запланированы выполняемые на вторичном потоке.

Цикл запуска

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

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

Рисунок 4-1  , Запускающий приложение в передний план
Application life cycle

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

Рисунок 4-2  , Запускающий приложение в фон

Чтобы определить, начинает ли Ваше приложение передний план или фон, проверьте applicationState свойство совместно используемого UIApplication объект в Вашем application:willFinishLaunchingWithOptions: или application:didFinishLaunchingWithOptions: метод делегата. Когда приложение запускается в передний план, это свойство содержит значение UIApplicationStateInactive. Когда приложение запускается в фон, свойство содержит значение UIApplicationStateBackground вместо этого. Можно использовать это различие для корректировки разового запуском поведения методов делегата соответственно.

Запуск в альбомном режиме

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

  • Добавьте UIInterfaceOrientation ключ к Вашему приложению Info.plist файл и набор значение этого ключа к также UIInterfaceOrientationLandscapeLeft или UIInterfaceOrientationLandscapeRight.

  • Разметьте свои представления в альбомном режиме и удостоверьтесь, что их опции расположения или автокалибровки установлены правильно.

  • Переопределите свой контроллер представления shouldAutorotateToInterfaceOrientation: метод и возврат YES для левых или правых альбомных ориентаций и NO для портретных ориентаций.

UIInterfaceOrientation ключ Info.plist файл говорит iOS, что он должен сконфигурировать ориентацию панели состояния приложения (если Вы выведены на экран), а также ориентация представлений, которыми управляют любые контроллеры представления во время запуска. Контроллеры представления уважают этот ключ и устанавливают начальную ориентацию их представления для соответствия. Используя этот ключ эквивалентно вызову setStatusBarOrientation:animated: метод UIApplication рано в выполнении Вашего applicationDidFinishLaunching: метод.

Установка специфичных для приложения файлов данных в первом запуске

Можно использовать первый цикл запуска приложения для установки любых данных или конфигурационных файлов, требуемых работать. Специфичные для приложения файлы данных должны быть созданы в Library/Application Support/<bundleID> / каталог Вашей тестовой среды приложения, где <bundleID> идентификатор пакета Вашего приложения. Можно далее подразделить этот каталог для организации файлов данных по мере необходимости. Можно также создать файлы в других каталогах, такой относительно каталога контейнера iCloud приложения или к локальной переменной Documents каталог, в зависимости от Ваших потребностей.

Если пакет Вашего приложения содержит файлы данных, которые Вы планируете изменить, копируете те файлы из комплекта приложений и изменить копии. Вы не должны изменять файлы в своем комплекте приложений. Поскольку приложения для iOS являются подписанным кодом, изменение файлов в Вашем комплекте приложений лишает законной силы подпись Вашего приложения и будет препятствовать тому, чтобы Ваше приложение запустилось в будущем. Копирование тех файлов к Application Support каталог (или другой перезаписываемый каталог в Вашей песочнице) и изменение их существуют единственный способ использовать такие файлы безопасно.

Для получения дополнительной информации о том, куда поместить связанные с приложением файлы данных, см. Руководство по программированию Файловой системы.

Когда Ваше приложение прервано временно, что сделать

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

Когда Ваше приложение попятилось к активному состоянию, applicationDidBecomeActive: метод должен инвертировать любой из шагов, принятых applicationWillResignActive: метод. Таким образом, на оживление, Ваше приложение должно перезапустить таймеры, очереди отгрузки резюме, и отрегулировать OpenGL частоты кадров ES снова. Однако игры не должны возобновляться автоматически; они должны остаться приостановленными, пока пользователь не принимает решение возобновить их.

Когда пользователь нажимает кнопку Sleep/Wake, приложения с файлами, защищенными NSFileProtectionComplete опция защиты должна закрыть любые ссылки на те файлы. Для устройств, сконфигурированных с надлежащим паролем, нажимая кнопку Sleep/Wake, блокирует экран и вынуждает систему выбросить ключи расшифровки для файлов с включенной полной защитой. В то время как экран заблокирован, любые попытки получить доступ к соответствующим файлам перестанут работать. Таким образом, если у Вас есть такие файлы, необходимо закрыть любые ссылки на них в Вашем applicationWillResignActive: метод и открытые новые ссылки в Вашем applicationDidBecomeActive: метод.

Ответ на временные прерывания

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

Рисунок 4-3  , Обрабатывающий основанные на предупреждении прерывания

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

Нажатие кнопки Sleep/Wake является другим типом прерывания, заставляющего Ваше приложение быть деактивированным временно. То, когда пользователь нажимает эту кнопку, система отключает сенсорные события, перемещает приложение в фон, устанавливает значение приложения applicationState свойство к UIApplicationStateBackground, и блокирует экран. Заблокированный экран имеет дополнительные последствия для приложений что защита данных использования для шифрования файлов. Те последствия описаны в том, Что Сделать, Когда Ваше Приложение Прервано Временно.

Когда Ваше приложение вводит передний план, что сделать

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

Рисунок 4-4  , Переходящий от фона до переднего плана

Будьте подготовлены обработать уведомления с очередями

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

Таблица 4-1 перечисляет уведомления, которые могут быть объединены и поставлены Вашему приложению. Большинство этих уведомлений поставлено непосредственно зарегистрированным наблюдателям. Некоторые, как связанные с изменениями ориентации устройства, обычно прерываются системной платформой и поставляются Вашему приложению в другом отношении.

Табличные 4-1  Уведомления, поставленные бодрствующим приложениям

Событие

Уведомления

Аксессуар соединяется или разъединяется.

EAAccessoryDidConnectNotification

EAAccessoryDidDisconnectNotification

Изменения ориентации устройства.

UIDeviceOrientationDidChangeNotification

В дополнение к этому уведомлению контроллеры представления обновляют свои интерфейсные ориентации автоматически.

Существует значительное изменение времени.

UIApplicationSignificantTimeChangeNotification

Уровень заряда батареи или изменения состояния батареи.

UIDeviceBatteryLevelDidChangeNotification

UIDeviceBatteryStateDidChangeNotification

Изменения состояния близости.

UIDeviceProximityStateDidChangeNotification

Состояние защищенных изменений файлов.

UIApplicationProtectedDataWillBecomeUnavailable

UIApplicationProtectedDataDidBecomeAvailable

Внешний дисплей соединяется или разъединяется.

UIScreenDidConnectNotification

UIScreenDidDisconnectNotification

Экранный режим дисплея изменяется.

UIScreenModeDidChangeNotification

Предпочтения, которые Ваше приложение представляет через измененное приложение Настроек.

NSUserDefaultsDidChangeNotification

Текущий язык или настройки локали изменились.

NSCurrentLocaleDidChangeNotification

Состояние учетной записи iCloud пользователя изменилось.

NSUbiquityIdentityDidChangeNotification

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

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

Обработайте Изменения iCloud

Если состояние изменений iCloud по какой-либо причине, система поставляет a NSUbiquityIdentityDidChangeNotification уведомление Вашему приложению. Состояние iCloud изменяется, когда пользователь входит в систему, или из iCloud считают, или включает или отключает синхронизацию документов и данных. Это уведомление является сигналом Вашего приложения для обновления кэшей и любых связанных с iCloud элементов пользовательского интерфейса для размещения изменения. Например, когда пользователь выходит из iCloud, необходимо удалить ссылки на все основанные на iCloud файлы или данные.

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

Изменения локали дескриптора

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

  • Используйте autoupdatingCurrentLocale метод класса при получении NSLocale объекты. Этот метод возвращает объект языкового стандарта, обновляющий себя автоматически в ответ на изменения, таким образом, Вы никогда не должны воссоздавать его. Однако, когда локаль изменяется, все еще необходимо обновить представления, содержащие содержание, полученное из текущей локали.

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

Для получения дополнительной информации об интернационализации Вашего кода для обработки изменений локали посмотрите Руководство по Интернационализации и Локализации.

Изменения дескриптора в настройках Вашего приложения

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

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

Когда Ваше приложение вводит фон, что сделать

При перемещении от переднего плана до фонового выполнения используйте applicationDidEnterBackground: метод Вашего приложения делегирует, чтобы сделать следующее:

Ваш делегат приложения applicationDidEnterBackground: метод имеет приблизительно 5 секунд для окончания любых задач и возврата. На практике этот метод должен возвратиться как можно быстрее. Если метод не возвращается, прежде чем время заканчивается, Ваше приложение уничтожено и очищено из памяти. При тихой необходимости в большем количестве времени для выполнения задач, вызовите beginBackgroundTaskWithExpirationHandler: метод, чтобы запросить фоновое время выполнения и затем запустить любые продолжительные задачи во вторичном потоке. Независимо от того, начинаете ли Вы какие-либо фоновые задачи, applicationDidEnterBackground: метод должен все еще выйти в течение 5 секунд.

В зависимости от функций Вашего приложения существуют другие вещи, которые Ваше приложение должно сделать при перемещении в фон. Например, любые активные службы Bonjour должны быть приостановлены, и приложение должно прекратить вызывать OpenGL функции ES. Для списка вещей Ваше приложение должно сделать при перемещении в фон, видеть Быть Ответственным Фоновым приложением.

Фоновый цикл перехода

То, когда пользователь нажимает кнопку «Домой», нажимает кнопку Sleep/Wake, или система запускает другое приложение, приоритетные переходы приложения к неактивному состоянию и затем к фоновому состоянию. Эти переходы приводят к вызовам делегату приложения applicationWillResignActive: и applicationDidEnterBackground: методы, как показано на рисунке 4-5. После возврата из applicationDidEnterBackground: метод, большинство приложений перемещается в состояние ожидания вскоре позже. Приложения, запрашивающие определенные фоновые задачи (такие как игра музыки) или тот запрос немного дополнительного времени выполнения от системы, могут продолжать работать некоторое время дольше.

Рисунок 4-5  , Перемещающийся от переднего плана до фона

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

Вскоре после делегата приложения applicationDidEnterBackground: возвраты метода, система берет снимок окон приложения. Точно так же, когда приложение разбужено для выполнения фоновых задач, система может взять новый снимок для отражения любых соответствующих изменений. Например, когда приложение разбужено для обработки загруженных элементов, система берет новый снимок так, чтобы мог отразить любые изменения, вызванные объединением элементов. Система использует эти изображения снимка в многозадачном UI для показа состояния приложения.

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

Сократите свой объем потребляемой памяти

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

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

Некоторые примеры объектов, которые необходимо удалить сильные ссылки, чтобы как можно скорее включать:

  • Объекты изображения Вы создали. (Некоторые методы UIImage возвратите изображения, данные основного изображения которых очищены автоматически системой. Для получения дополнительной информации посмотрите обсуждение в обзоре Ссылки класса UIImage.)

  • Большие носители или файлы данных, которые можно загрузить снова из диска

  • Любые другие объекты, в которых Ваше приложение не нужно и может воссоздать легко позже

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

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

  • Это удаляет любые системные ссылки на кэшируемые изображения.

  • Это удаляет сильные ссылки к некоторым другим кэшам системных управляемых данных.