Что происходит с сокетами, когда iOS-приложение уходит в фоновый режим

Итак, допустим, у нас есть приложение, в котором открыт TCP-сокет, мы в него читаем/пишем данные, и тут внезапно пользователь нажимает на кнопку Home. Что произойдет дальше?

Для начала надо вспомнить, в каких состояниях может находиться приложение. Состояния следующие (я немного отойду от терминологии Apple):

  • running: ну здесь все понятно
  • inactive: то же самое, что и running, но в приложение не приходят никакие event'ы от пользователя
  • backgrounded: то же самое, что и running, но приложения нет на экране, не приходят event'ы от пользователя, и уже нельзя пользоваться некоторыми API (например, OpenGL).
  • suspended: то же самое, что и backgrounded, приложение находится в памяти, но ОС больше не шедулит нисколько времени ни на один поток приложения, т.е. никакой ваш код приложения больше не выполняется
  • hibernated: если приложение в состоянии supspended занимало менее 16MB dirty memory, то оно может быть полностью со всеми страницами выгружено на диск и впоследствии быть полностью восстановлено
  • not running/: если приложение в состоянии supspended занимало более 16MB dirty memory, то его процесс просто убивается и при последующем обращении приложение будет запущено заново.

Допустим, пользователь нажал на кнопку Home. Дальше приложение переходит в состояние backgrounded, и

  • если в Info.plist не установлен ни один из background режимов (audio, voip, location и другие), то приложение очень быстро перейдет в состояние supspended
  • если в Info.plist не установлен ни один из background режимов, но мы в методе applicationDidEnterBackground специально регистририум background-task, то ещё примерно 10 минут приложение может заниматься своими делами в бэкграунде, после чего перейдёт в состояние suspended
  • если в Info.plist установлен какой-нибудь background режим (audio, voip, location или другой), приложение может заниматься своими делами в бэкграунде сколько хочет (замечание: для audio режима приложение должно на самом деле проигрывать аудио, если оно это делать перестанет, то может быть перемещено в состояние suspended)

Итак, что собственно может происходить с сокетом?

  • running: всё хорошо
  • inactive: всё хорошо
  • backgrounded: тоже всё хорошо
  • not running/killed: тоже всё хорошо, т.к. приложения нет, и проблемы больше нет :)
  • suspended: приложение не получает никаких циклов процессора, однако же данные по сети к нам в девайс продолжают приходить. Здесь возможны 3 варианта, по сути ведущие к 2 исходам:
  • ядро продолжает получать данные и накапливает их в каком-то своем буфере, сокет продолжает оставаться живым. Если мы возвращаемся в приложение, ядро выплевывает нам накопившиеся данные, как будто состояния suspended и не было
  • если у ядра заканчивается место под буферы, оно просто прибивает сокет, и когда мы возвращаемся в приложение, нам сокетный делегат/каллбэк вернет ошибку
  • ОС по собственной инициативе может просто прибить сокет, и когда мы возвращаемся в приложение, нам сокетный делегат/каллбэк вернет ошибку.

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