Стратегии реализации определенных функций приложения

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

Стратегии конфиденциальности

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

Защита данных Используя дисковое шифрование

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

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

  • Файловая система на устройстве пользователя должна поддерживать защиту данных. Большинство устройств поддерживает это поведение.

  • У пользователя должен быть активный набор блокировки кода доступа для устройства.

Для защиты файла Вы добавляете атрибут к файлу, указывающему желаемый уровень защиты. Добавьте этот атрибут с помощью любого NSData класс или NSFileManager класс. При записи новых файлов можно использовать writeToFile:options:error: метод NSData с надлежащей защитой оценивают как одна из опций записи. Для существующих файлов можно использовать setAttributes:ofItemAtPath:error: метод NSFileManager установить или изменить значение NSFileProtectionKey. При использовании этих методов укажите один из следующих уровней защиты для файла:

  • Когда устройство заблокировано, никакая защита — файл шифруется, но не защищен кодом доступа и доступен. Укажите NSDataWritingFileProtectionNone опция (NSData) или NSFileProtectionNone атрибут (NSFileManager).

  • В то время как устройство заблокировано, завершенный — файл шифруется и недоступен. Укажите NSDataWritingFileProtectionComplete опция (NSData) или NSFileProtectionComplete атрибут (NSFileManager).

  • Завершенный, если уже не открываются — файл шифруется. В то время как устройство заблокировано, закрытый файл недоступен. После того, как пользователь разблокировал устройство, Ваше приложение может открыть файл и использовать его. Если пользователь блокирует устройство, в то время как файл открыт, тем не менее, Ваше приложение может продолжать получать доступ к нему. Укажите NSDataWritingFileProtectionCompleteUnlessOpen опция (NSData) или NSFileProtectionCompleteUnlessOpen атрибут (NSFileManager).

  • Завершенный до первого входа в систему — файл шифруется и недоступен, пока устройство не загрузилось, и пользователь разблокировал его один раз. Укажите NSDataWritingFileProtectionCompleteUntilFirstUserAuthentication опция (NSData) или NSFileProtectionCompleteUntilFirstUserAuthentication атрибут (NSFileManager).

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

Для новых файлов рекомендуется включить защиту данных прежде, чем записать любые данные им. Если Вы используете writeToFile:options:error: метод для записи содержания NSData возразите против диска, это происходит автоматически. Для существующих файлов, добавляя защиту данных заменяет незащищенный файл новой защищенной версией.

Идентификация уникальных пользователей приложения

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

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

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

  • Вы хотите дифференцировать экземпляры своего приложения, работающего на различных устройствах. Используйте identifierForVendor свойство UIDevice класс для получения ID, дифференцирующего пользователя на одном устройстве от пользователей на других устройствах. Этот метод действительно теперь позволяет Вам идентифицировать определенных пользователей. У отдельного пользователя могут быть многократные устройства, каждый с различным Значением идентификатора.

  • Вы хотите идентифицировать пользователя в целях распространения. Используйте advertisingIdentifier свойство ASIdentifierManager класс для получения ID для пользователя.

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

Поддержка Многократных Версий iOS

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

Существует несколько типов проверок, которые можно осуществить:

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

Сохранение визуального появления приложения через запуски

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

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

Существует три места, где необходимо думать о сохранении состояния в приложении:

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

Включение сохранения состояния и восстановления в приложении

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

Обычно, Ваши реализации этих методов просто возвращаются YES указать, что могут произойти сохранение состояния и восстановление. Однако приложения, хотящие сохранить и восстановить их состояние условно, могут возвратиться NO в ситуациях, где не должны происходить операции. Например, после выпуска обновления к Вашему приложению, Вы могли бы хотеть возвратиться NO от Вашего application:shouldRestoreApplicationState: метод, если Ваше приложение неспособно полезно восстановить состояние от предыдущей версии.

Процесс сохранения и восстановления

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

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

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

Во время процесса сохранения и восстановления Ваше приложение имеет ряд ответственности.

  • Во время сохранения Ваше приложение ответственно за:

    • Сообщение UIKit, что это поддерживает сохранение состояния.

    • Сообщение UIKit, просматривающих контроллеры и представления, должно быть сохранено.

    • Кодирование соответствующих данных для любых сохраненных объектов.

  • Во время восстановления Ваше приложение ответственно за:

    • Сообщение UIKit, что это поддерживает восстановление состояния.

    • Обеспечение (или создание) объекты, которые требует UIKit.

    • Декодирование состояния сохраненных объектов и использование его для возврата объекта его предыдущему состоянию.

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

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

Рисунок 5-1  демонстрационная иерархия контроллера представления

UIKit сохраняет только те объекты, имеющие присвоенный идентификатор восстановления. Идентификатор восстановления является строкой, идентифицирующей контроллер представления или представления для UIKit и Вашего приложения. Значение этой строки является значительным только к Вашему коду, но присутствие этой строки говорит UIKit, что должно сохранить маркированный объект. Во время процесса сохранения UIKit обходит иерархию контроллера представления Вашего приложения и сохраняет все объекты, имеющие идентификатор восстановления. Если контроллер представления не имеет идентификатора восстановления, того контроллера представления и всех его представлений, и дочерние контроллеры представления не сохраняются. Рисунок 5-2 показывает, что обновленная версия предыдущей иерархии представления, теперь с восстановлением идентифицирует, применился к большинству (но не все) контроллеров представления.

  Восстановление Добавления рисунка 5-2 идентифицирует для просмотра контроллеров

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

Для каждого контроллера представления Вы принимаете решение сохранить, также необходимо решить, как Вы хотите восстановить его позже. UIKit предлагает два способа воссоздать объекты. Можно позволить приложению делегировать, воссоздают его, или можно присвоить класс восстановления контроллера представления и позволить тому классу воссоздать его. Класс восстановления реализует UIViewControllerRestoration протокол и ответственен за нахождение или создание заданного объекта во время восстановления. Вот некоторые подсказки для того, когда использовать каждого:

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

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

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

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

Поток процесса сохранения

Рисунок 5-3 показывает высокоуровневые события, происходящие во время сохранения состояния, и показывает, как затронуты объекты Вашего приложения. Прежде чем сохранение даже происходит, UIKit спрашивает Вашего делегата приложения, если это должно произойти путем вызова application:shouldSaveApplicationState: метод. Если возвращается тот метод YES, UIKit начинает собирать и кодировать представления Вашего приложения и контроллеры представления. Когда это закончено, это пишет закодированные данные в диск.

  Высокий уровень рисунка 5-3 течет интерфейсное сохранение

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

Поток процесса восстановления

Рисунок 5-4 показывает высокоуровневые события, происходящие во время восстановления состояния, и показывает, как затронуты объекты Вашего приложения. После стандартной инициализации и загрузки UI завершено, UIKit спрашивает Вашего делегата приложения, если восстановление состояния должно произойти вообще путем вызова application:shouldRestoreApplicationState: метод. Это - Ваша возможность делегата приложения исследовать сохраненные данные и определить, возможно ли восстановление состояния. Если это, UIKit использует делегата приложения и классы восстановления для получения ссылок на контроллеры представления приложения. Каждый объект тогда предоставлен данными, которые он должен восстановить сам к его предыдущему состоянию.

  Высокоуровневый поток рисунка 5-4 для восстановления Вашего пользовательского интерфейса

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

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

Что происходит когда Вы Exclude Groups контроллеров представления?

Когда идентификатор восстановления контроллера представления nil, тот контроллер представления и любые дочерние контроллеры представления, которыми это управляет, не сохраняются автоматически. Например, на рисунке 5-5, потому что контроллер навигации не имел идентификатора восстановления, он и все его дочерние контроллеры представления и представления опущен от сохраненных данных.

  Контроллеры представления Excluding рисунка 5-5 от автоматического процесса сохранения

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

Рисунок 5-6  , Загружающий набор по умолчанию контроллеров представления

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

Контрольный список для реализации сохранения состояния и восстановления

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

При добавлении сохранения состояния и восстановления к коду, используйте следующий список для напоминания Вам о коде, который необходимо записать.

Включение сохранения состояния и восстановления в приложении

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

Обычно, Ваши реализации этих методов просто возвращаются YES указать, что могут произойти сохранение состояния и восстановление. Однако приложения, хотящие сохранить и восстановить их состояние условно, могут возвратиться NO в ситуациях, где не должны происходить операции. Например, после выпуска обновления к Вашему приложению, Вы могли бы хотеть возвратиться NO от Вашего application:shouldRestoreApplicationState: метод, если Ваше приложение неспособно полезно восстановить состояние от предыдущей версии.

Сохранение состояния контроллеров представления

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

Отмечание контроллеров представления для сохранения

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

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

Когда это просит, чтобы Вы обеспечили контроллер представления, UIKit предоставляет Вам тракт восстановления объекта контроллера представления. Тракт восстановления является последовательностью идентификаторов восстановления, запускающихся в корневом контроллере представления и спускающихся с иерархии контроллера представления к текущему объекту. Например, предположите, что у Вас есть контроллер панели вкладок, идентификатор восстановления которого TabBarControllerID, и первая вкладка содержит контроллер навигации, идентификатор которого NavControllerID и то, корень которого просматривает идентификатор контроллера, MyViewController. Полный тракт восстановления для корневого контроллера представления был бы TabBarControllerID/NavControllerID/MyViewController.

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

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

Восстановление контроллеров представления во время запуска

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

  1. Если контроллер представления имел класс восстановления, UIKit просит что класс обеспечивать контроллер представления. UIKit вызывает viewControllerWithRestorationIdentifierPath:coder: метод связанного класса восстановления для получения контроллера представления. Если возвращается тот метод nil, предполагается, что приложение не хочет воссоздавать контроллер представления, и UIKit прекращает искать его.

  2. Если контроллер представления не имел класса восстановления, UIKit просит, чтобы делегат приложения обеспечил контроллер представления. UIKit вызывает application:viewControllerWithRestorationIdentifierPath:coder: метод Вашего приложения делегирует для поиска контроллеров представления без класса восстановления. Если возвращается тот метод nil, UIKit пытается найти контроллер представления неявно.

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

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

Стоит отметить, что при указании класса восстановления для контроллера представления UIKit не пытается найти контроллер представления неявно. Если viewControllerWithRestorationIdentifierPath:coder: метод Ваших возвратов класса восстановления nil, UIKit прекращает пытаться определить местоположение Вашего контроллера представления. Это дает Вам контроль, хотите ли Вы действительно создать контроллер представления. Если Вы не указываете класс восстановления, UIKit делает все, что он может для нахождения контроллера представления для Вас, создавая его по мере необходимости из файлов раскадровки Вашего приложения.

Если Вы принимаете решение использовать класс восстановления, реализацию Вашего viewControllerWithRestorationIdentifierPath:coder: метод должен создать новый экземпляр класса, выполнить некоторую минимальную инициализацию и возвратить полученный объект. Перечисление 5-1 показывает пример того, как Вы могли бы использовать этот метод для загрузки контроллера представления из раскадровки. Поскольку контроллер представления был первоначально загружен из раскадровки, этот метод использует UIStateRestorationViewControllerStoryboardKey ключ для получения раскадровки от архива. Обратите внимание на то, что этот метод не пытается сконфигурировать поля данных контроллера представления. Когда состояние контроллера представления декодируется, тот шаг происходит позже.

Перечисление 5-1  , Создающее новый контроллер представления во время восстановления

+ (UIViewController*) viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents
                      coder:(NSCoder *)coder {
   MyViewController* vc;
   UIStoryboard* sb = [coder decodeObjectForKey:UIStateRestorationViewControllerStoryboardKey];
   if (sb) {
      vc = (PushViewController*)[sb instantiateViewControllerWithIdentifier:@"MyViewController"];
      vc.restorationIdentifier = [identifierComponents lastObject];
      vc.restorationClass = [MyViewController class];
   }
    return vc;
}

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

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

Кодирование и декодирование состояния контроллера представления

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

  • Ссылки на любые выводимые на экран данные (не сами данные)

  • Для контейнерного контроллера представления, ссылок на его дочерние контроллеры представления

  • Информация о текущем выборе

  • Для контроллеров представления с конфигурируемым пользователем представлением, информацией о текущей конфигурации того представления.

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

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

  Кодирование перечисления 5-2 и декодирование состояния контроллера представления.

- (void)encodeRestorableStateWithCoder:(NSCoder *)coder {
   [super encodeRestorableStateWithCoder:coder];
 
   [coder encodeInt:self.number forKey:MyViewControllerNumber];
}
 
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder {
   [super decodeRestorableStateWithCoder:coder];
 
   self.number = [coder decodeIntForKey:MyViewControllerNumber];
}

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

Для получения дополнительной информации о реализации Вашего кодировать и декодируйте методы для своих контроллеров представления, смотрите Ссылку класса UIViewController.

Сохранение состояния представлений

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

Чтобы определять, что состояние представления должно быть сохранено, Вы делаете следующее:

  • Присвойте допустимую строку представлению restorationIdentifier свойство.

  • Используйте представление от контроллера представления, также имеющего допустимый идентификатор восстановления.

  • Для табличных представлений и представлений набора, присвойте источник данных, принимающий UIDataSourceModelAssociation протокол.

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

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

Представления UIKit с состоянием Preservable

Для сохранения состояния любого представления, и включая пользовательские и включая стандартные системные представления, необходимо присвоить идентификатор восстановления представлению. Представления без идентификатора восстановления не добавляются к списку preservable объектов UIKit.

Следующие представления UIKit имеют информацию состояния, которая может быть сохранена:

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

Сохранение состояния пользовательского представления

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

Перечисление 5-3 показывает пример того, как сохранить и восстановить выбор для пользовательского представления, содержащего доступный для редактирования текст. В примере диапазон является доступным использованием selectionRange и setSelectionRange: методы, которые являются пользовательскими методами использование представления для управления выбором. Кодирование данных только требует записи его к предоставленному объекту кодера. Восстановление данных требует чтения его и применения его к представлению.

Перечисление 5-3  , Сохраняющее выбор представления пользовательского текста

// Preserve the text selection
- (void) encodeRestorableStateWithCoder:(NSCoder *)coder {
    [super encodeRestorableStateWithCoder:coder];
 
    NSRange range = [self selectionRange];
    [coder encodeInt:range.length forKey:kMyTextViewSelectionRangeLength];
    [coder encodeInt:range.location forKey:kMyTextViewSelectionRangeLocation];
}
 
// Restore the text selection.
- (void) decodeRestorableStateWithCoder:(NSCoder *)coder {
   [super decodeRestorableStateWithCoder:coder];
   if ([coder containsValueForKey:kMyTextViewSelectionRangeLength] &&
           [coder containsValueForKey:kMyTextViewSelectionRangeLocation]) {
      NSRange range;
      range.length = [coder decodeIntForKey:kMyTextViewSelectionRangeLength];
      range.location = [coder decodeIntForKey:kMyTextViewSelectionRangeLocation];
      if (range.length > 0)
         [self setSelectionRange:range];
   }
}

Реализация благоприятных для сохранения источников данных

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

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

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

Сохранение высокоуровневого состояния приложения

В дополнение к данным, сохраненным контроллерами и представлениями представления Вашего приложения, UIKit предоставляет рычаги Вам для сохранения любых разных данных, необходимых приложению. В частности, UIApplicationDelegate протокол включает следующие методы для Вас для переопределения:

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

Подсказки для сохранения и восстановления информации состояния

Поскольку Вы добавляете поддержку сохранения состояния и восстановления к Вашему приложению, рассматриваете следующие инструкции:

  • Закодируйте информацию о версии вместе с остальной частью состояния Вашего приложения. Во время процесса сохранения рекомендуется закодировать строку версии или число, идентифицирующее текущую версию пользовательского интерфейса приложения. Можно закодировать это состояние в application:willEncodeRestorableStateWithCoder: метод Вашего делегата приложения. Когда Ваш делегат приложения application:shouldRestoreApplicationState: метод вызывают, можно получить эту информацию от предоставленного кодера и использовать его, чтобы определить, возможно ли сохранение состояния.

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

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

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

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

  • Когда пользовательская сила выходит из приложения, система автоматически удаляет сохраненное состояние приложения. Удаление сохраненной информации состояния, когда приложение уничтожается, является мерами безопасности. (Как меры безопасности, система также удаляет сохраненное состояние если сбои приложения дважды во время запуска.), Если Вы хотите протестировать возможность своего приложения восстановить ее состояние, Вы не должны использовать многозадачную панель для уничтожения приложения во время отладки. Вместо этого используйте XCode, чтобы уничтожить приложение или уничтожить приложение программно путем установки временной команды или жеста для вызова exit по требованию.

Подсказки для разработки приложения VoIP

Приложение Передачи речи по протоколу IP (VoIP) позволяет пользователю выполнять телефонные вызовы с помощью Интернет-соединения вместо услуги сотовой связи устройства. Такое приложение должно поддержать персистентное сетевое соединение со своей связанной службой так, чтобы оно могло получить входящие вызовы и другие соответствующие данные. Вместо того, чтобы не давать спать приложениям VoIP все время, система позволяет им быть приостановленными и предоставляет средства для контроля их сокетов для них. Когда входящий трафик обнаруживается, система будит приложение VoIP и возвращает управление его сокетов к нему.

Существует несколько требований для реализации приложения VoIP:

  1. Включите фоновый режим Речи по IP для своего приложения. (Поскольку приложения VoIP включают звуковое содержимое, рекомендуется также включить фоновый режим Аудио и AirPlay.) Вы включаете фоновые режимы на вкладке Capabilities Вашего проекта XCode.

  2. Сконфигурируйте один из сокетов приложения для использования VoIP.

  3. Прежде, чем переместиться в фон, вызовите setKeepAliveTimeout:handler: метод для установки обработчика, который будет периодически выполняться. Ваше приложение может использовать этот обработчик для поддержания его соединения услуг.

  4. Сконфигурируйте свой аудио сеанс для обработки переходов к и от активного использования.

  5. Для обеспечения лучшего пользовательского опыта в iPhone используйте Базовую платформу Телефонии для корректировки поведения в связи с основанными на ячейке телефонными вызовами; посмотрите Базовую Ссылку Платформы Телефонии.

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

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

Конфигурирование сокетов для использования VoIP

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

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

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

Таблица 5-1  , Конфигурирующая поток, взаимодействует через интерфейс для использования VoIP

Интерфейс

Конфигурация

NSInputStream и NSOutputStream

Для потоков Какао используйте setProperty:forKey: метод для добавления NSStreamNetworkServiceType свойство к потоку. Значение этого свойства должно быть установлено в NSStreamNetworkServiceTypeVoIP.

NSURLRequest

При использовании загрузочной системы URL используйте setNetworkServiceType: метод Вашего NSMutableURLRequest возразите для установки типа сетевой службы запроса. Тип службы должен быть установлен в NSURLNetworkServiceTypeVoIP.

CFReadStreamRef и CFWriteStreamRef

Для Базовых потоков Основы используйте CFReadStreamSetProperty или CFWriteStreamSetProperty функция для добавления kCFStreamNetworkServiceType свойство к потоку. Значение для этого свойства должно быть установлено в kCFStreamNetworkServiceTypeVoIP.

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

Для получения дополнительной информации о конфигурировании потоковых объектов Какао, см. Потоковое Руководство по программированию. Для получения информации об использовании URL-запросов см. Руководство по программированию Загрузочной системы URL. И для получения информации о конфигурировании потоков с помощью интерфейсов CFNetwork, см. Руководство по программированию CFNetwork.

Установка обработчика проверки активности

Для предотвращения потери его соединения приложение VoIP обычно должно периодически просыпаться и регистрация с его сервером. Для упрощения этого поведения iOS позволяет Вам установить специальный обработчик с помощью setKeepAliveTimeout:handler: метод UIApplication. Вы обычно устанавливаете этот обработчик в applicationDidEnterBackground: метод Вашего делегата приложения. После того, как установленный, системные вызовы Ваш обработчик, по крайней мере, однажды интервал тайм-аута истекает, будя Ваше приложение по мере необходимости, чтобы сделать так.

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

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

Конфигурирование аудио сеанса приложения

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

Для получения информации о том, как сконфигурировать и управлять аудио сеансом для приложения VoIP, видит Аудио Руководство по программированию Сеанса.

Используя интерфейсы достижимости для улучшения пользовательского опыта

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

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

  1. Создайте a SCNetworkReachabilityRef структура для Вашего целевого удаленного узла.

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

  3. Добавьте что цель к активному циклу выполнения Вашего приложения (такого как основной цикл выполнения) использование SCNetworkReachabilityScheduleWithRunLoop функция.

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

Для получения дополнительной информации об интерфейсах достижимости, посмотрите Ссылку Платформы Конфигурации системы.