Жизненый цикл приложения iOS

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

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

Фреймворки iOS полагаются на паттерн MVC и делегируют эту реализацию. Понимание этих паттернов разработки это ключ к успешной разработки приложений. Это так же помогает в знакомстве с Objective-C и его возможностями. Если вы новичок в iOS программировании, то предлагаем почитать Start Developing iOS Apps Today для введения в iOS приложения и язык Objective-C.

Основная функция

Входной точкой в каждом приложении основанном на C является функция main в iOS приложениях это правильно так же соблюдается. Единственное чем отличается, это то, что в iOS прилоежении вы не должны писать в функцию main самостоятельно. Xcode создает эту функцию как часть основы для вашего проекта. Листинг 2-1 показывает пример этой функции. За исключением нескольких случаев, вы никогда не должны изменять реализацию функции main предоставляемой Xcode.

Листинг 2-1 Функция main приложения iOS

#import 
#import "AppDelegate.h"
int main(int argc, char * argv[])  
{
  @autoreleasepool {
      return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
  }
}

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

Структура приложения

Во время запуска, функция UIApplicationMain выбирает несколько ключевых объектов и запускает приложение. В сердце каждого iOS приложения лежит объект UIApplication, который способствует взаимодействию между системой и другими объектами приложения. Рисунок 2-1 показывает основные объекты которые можно найти в большинстве приложений, Таблица 2-1 описывает роли которые играет каждый объект. Обратите внимание, что iOS приложение использует MVC архитектуру. Этот паттерн отделяет данные приложение от бизнес-логики и визуальным представлением данных. Эта архитектура ключевая в создании приложения, которое способно запускаться на различных устройствах с различными размерами экрана.

Рисунок 2-1 Ключевые объекты iOS приложения

Таблица 2-1 Роли объектов в iOS приложении

Объект Описание
UIApplication Объект UIApplication управляет циклом событий и другими  высокоуровневыми поведением приложения. Он так же сообщает ключ транзакций приложения и некоторые специальные события (такие как приход push-уведомлений) для их делигирования, каждому пользовательскому объекту который вы укажите. Использует объект UIApplication без наследования.
App delegate App delegate это сердце вашего кода. Этот объект работает в тандеме с объектом UIApplication во время инициализации, передач, и различных выскоуровневых событиях приложения. Этот объект так же единственный который гарантированно присутствует в каждом приложении, поэтому он часто используется чтобы установить начальные структуры данных приложения.
Documents и data model Data model хранит данные вашего приложения и является уникальным для вашего приложения. Например, в банковском приложении может храниться база финансовых операций, в то время как приложение для рисования может хранить изображение объекта или даже историю команд рисования, которые привели к созданию этого изображения. (В последнем случае объект изображения по прежнему объект данных, потому что Data model всего лишь контейнер для данных изображения) Приложение так же может использовать объекты document (Наследованный класс от UIDocument) управляющий некоторыми или всеми его объектами Data model. Объекты Document не обязательны, но предлагают удобный способ для группировки данных, которые принадлежат одному файлу или пакету файлов. Для большей информации читайте Document-Based App Programming Guide for iOS.
View controller View controller управляет отображением данных вашего приложения на экране. View controller управляет одним единственным View и его набором view. Когда происходит отображение, View controller делает view видимыми и устанавливает их в окне приложения. Класс UIViewController является основным классом для всех объектов view controller. Это обеспечивает функциональность по умолчанию для загрузки view, их отображения, поворота во время поворота устройства, и некоторые другие поведения системы. UIKit и другие фреймворки определяют дополнительный класс view controller реализующий стандартный системный интерфейс такой как выбор изображения, интерфейс с вкладками и навигационный интерфейс. Для более детальной информации о view controller, смотрите в View Controller Programming Guide for iOS.
UIWindow Объект UIWindow координирует показом одного или более views на экране. Большинство приложений имеет один объект window, который отображает данные основного экрана, но приложения могут иметь дополнительные window для отображения данных на дополнительных экранах. Чтобы изменить данные вашего приложения, используйте view controller для изменения отображаемых данный в соответствующем window. Никогда не перемещается сам window. В дополнение в hosting view, window работает с объектом  UIApplication доставляющее события в ваши view и view controller-ы.
View, control, и layer объекты View и control-ы предоставляют визуальное представление данных вашего приложения. view это объект рисующий данные в разрабатываемой квадратной зоне и возвращает события из этой зоны. Control-ы это специализированный тип view ответственный за реализацию привычных объектов интерфейса таких как кнопки, текстовые поля или переключатели. Фреймворк UIKit предоставляет стандартные view для отображения различных типов данных. Вы можете переопределить свои собственные view путем наследования непосредственно от класса UIView (или  от его потомков). В дополнение включению view и control, приложение может также включать слои Core Animation со своими иерархиями view и control. Объекты Layer на самом деле являются объектами data для отображения визуальных данных. View используют объекты layer в фоне прежде чем отобразить. Вы так же можете добавить свой собственный объект layer для реализации сложной анимации вашего интерфейса или други типов визуальных эффектов.

Чем отлично одно iOS приложение от другого, это управление данными (и соответствующая бизнес-логика) и то как они представляются пользователю. Большинство взаимодействий объектов UIKit не определяет ваше приложение, но помогает вам усовершенствовать его поведение. Например, методы вашего приложения делегируются когда приложение изменение состояние, что вы определяет в своем коде чтобы отреагировать соответствующим образом.

Основной цикл работы

Основной цикл работы приложения обрабатывает все пользовательские события. Объект UIApplication запускает основной цикл с момента запуска и использует его для обработки события и обработки изменений в интерфейсе. Как следует из названия, основной цикл выполняется в основном потоке приложения. Такое поведение гарантирует, что события связные с пользователем будут обрабатываться последовательно в том порядке в котором они были получены.

На рисунке 2-2 изображена архитектура основного цикла и то как совершается обработка пользовательских событий после их получения в вашем приложении. Когда пользователь взаимодействует с устройством, события, связанные с этим взаимодействием генерируются системой через специальный порт созданный UIKit. События помещаются в очередь внутри приложения и направляются один за другим в основной цикл для исполнения. Объект UIApplication это первый объект который принимает события и принимает решение о том, что с ним должно быть сделано. События касания (touch) обычно направляется на объект главного окна, которое в свою очередь пересылает это сообщение в view, в котором произошло это касание. Другие события могут быть приняты немного другим путями через различные объекты приложения.

Рисунок 2-2 Обработка событий в основном цикле

Много типов событий может поставляться в приложение iOS. Основная их часть отображена в таблице 2-2. Много этих типов событий поставляются используя основной цикл, но некоторые нет. Некоторые события отсылаются непосредственно в объект или отправлены в блокировку что вы предоставите. Для информации о основных типах событий, включая касания, удаленное управление, движение, акселерометр и гироскоп - смотрите в Event Handling Guide for iOS.

Таблица 2-2 Основные типы событий в приложении iOS

Тип события Поставляется в... Замечания
Касание Объект view на который было совершено нажатие View принимающий объект. Любое событие связанное с касанием не обрабатываются View а отправляются дальше по цепочке для обработки.
Удаленное управление Событие встряхивания Первый ответивший объект События удаленного управления существуют для управлением проигрыванием медиа и генерируемые наушниками или другими аксессуарами.
Акселерометр Магнитометр Гироскоп Объект который вы указали События созданные акселерометром, магнитометром и гироскопом отправляются в объект который вы указали.
Локация Объект который вы указали Вы регистрируете прием событий локации используя фреймворк Core Location. Для большей информации о использовании Core Location, смотрите [Location and Maps Programming Guide](https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/Introduction/Introduction.html#//apple_ref/doc/uid/TP40009497).
Перерисовать View который необходимо перерисовать События перерисовки не вызываются объектами событий, но могу быть вызваны самим View для перерисовки самого себя. Архитектура рисования iOS описана в [Drawing and Printing Guide for iOS](https://developer.apple.com/library/ios/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/Introduction/Introduction.html#//apple_ref/doc/uid/TP40010156).

Некоторые события, такие как касание или удаленное управление, могут приниматься ответившими объектами (responder objects). Такие объекты везде в вашем приложении. (Объект UIApplication, ваш view объект, и ваш view controller объекты, все примеры ответивших объектов.) Основными целями событий являются ответившие объекты, но могут быть переданы другими ответившими объектами (через цепочку ответивших (responder chain)) если вам нужно обработать события. Например, view не имеет перехватчика, событие может передать событие через superview или view controller.

Событие касания происходящие в controls (таких как кнопки) и обрабатываются иначе, чем в события касания происходящие на многих других типах view. Как правило, только на ограниченное число взаимодействий возможно с control,  и эти события упакованы в action сообщения и отправляются в соответсвующий целевой объект. Этот паттерн, называемый target-action упрощает использование control-ов для включение вашего кода в приложении.

Стадии работы приложения

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

Таблица 2-3 Стадии приложения

Стадия Описание
Not running Приложение не было запущено или было выключено системой.
Inactive Приложение запущено, но сейчас не принимает события. (Это может произойти из за запуска другого кода.) Приложение обычной остается в этом состоянии только только на короткий промежуток времени, для перехода между состояниями.
Active Приложение запущено и принимает события. Это нормальный режим для запущенных приложений.
Background Приложение находиться фоне и обрабатывает код. Большинство приложений попав в это состояние ненадолго прежде чем попасть в состояние suspended. Тем не менее, приложение, которое запрашивает дополнительное время, может оставаться в течении определенного периода времени в этом состоянии. Кроме того, приложение запущенное непосредственно из этого состояния переходит в состояние inactive. Для информации о том как работает код в этом состоянии читайте [Background Execution](https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html#//apple_ref/doc/uid/TP40007072-CH4-SW1).
Suspended Приложение в фоне, но не выполняющее код. Система перемещает приложение в это состояние автоматически и не оповещает его об этом. Когда приложение в suspended, приложение остается в памяти, но не выполняет какой либо код. Когда возникают события с нехваткой памяти, система может удалить приложения не оповестив его, для того чтобы освободить больше места для открываемых приложений.

Рисунок 2-3 Изменение состояний приложения iOS

Основные перемещения между состояния вызывают определенные методы указанные в объекте приложения. Эти методы дают вам возможность обработать изменение состояний. Эти методы описаны ниже вместе с тем как вы можете использовать их

  • application:willFinishLaunchingWithOptions:— Этот метод вашего приложения позволяет вам выполнять код во время запуска приложения.

  • application:didFinishLaunchingWithOptions: — Этот метод позволяет вам перед окончанием запуска выполнить код прежде чем показать ваше приложение пользователю.

  • applicationDidBecomeActive: — Дает вам знать, что оно становятся foreground приложением. Используйте этот метод для последних приготовлений.

  • applicationWillResignActive: — Дает вам значит, что приложение уходит из состояния foreground. Используйте этот метод для помещения вашего приложения в режим покоя.

  • applicationDidEnterBackground: — Дает вам знать, что приложение запущено в фоне и может быть выключено в любое время.

  • applicationWillEnterForeground: — Дает вам знать, что ваше приложение перемещено из фона обратно в foreground, но то, что оно еще не активно.

  • applicationWillTerminate: — Дает вам знать, что приложение было выключено. Этот метод не вызывается, если приложение было в состоянии suspended.

Выключение приложения

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

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

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

Потоки и параллельная работа

Система создает приложение в основном потоке и вы можете создавать отдельные потоки, если вам это необходимо, для решения каких либо задач. Для приложений iOS, предпочтительным методом является использование Grand Central Dispatch (GCD), оперирущим с объектами, и другиим интерфейсами асинхронного программирования не создавая и управляя потоками собственоручно. Такие технологии как GCD позволяют определить работу, которую вы хотите сделать и в каком порядке вы хотите ее сделать, но пусть система решает как лучше выполнить эту работу для CPU. Когда система управляет вашими потоками вам становиться легче писать кот, обспечивается большая корректность кода, а так же увеличивает общую производительность.

Когда мы думает о потоках и парралельной работе, необхоимо учитывать следующее:

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

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

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

Для больше информации о использовании GCD и оперирующим объектам, обратитесь к Concurrency Programming Guide.