вторник, 5 апреля 2011 г.
iOS 4.x - коварная многозадачность
Не разделяю я восторгов общественности по поводу появления многозадачности для юзерских приложений (сама по себе ОС была многозадачной изначально, с предками из знатного рода BSD Unix), но что ж поделать - с такой теперь нам жить.
В связи с тем что реализовали ее не совсем стандартно, то и проблемы, возникающие с ней уникальны только для iOS.
Итак, что было до появления iOS 4.x:
- у приложения был делегат applicationWillTerminate, который вызывался как только юзер нажал кнопку Home, в нем мы корректно обрабатывали выход, сохраняли состояние приложения и отдавали управление ОС. Всё понятно, всё логично.
С выходом iOS 4.x мы получили новые делегаты и двоякое поведение приложения
Сценарий поведения 1:
Если в info.plist приложения параметр UIApplicationExitsOnSuspend установлен в YES - мы по-прежнему можем надеяться на вызов делегата applicationWillTerminate, корректно его обработаем итп, но увы, никакой поддержки многозадачности не получим.
Сценарий поведения 2:
Если в info.plist приложения параметр UIApplicationExitsOnSuspend установлен в NO (либо отсутствует), то
- при нажатии на Home делегат applicationWillTerminate больше никогда не вызывается
- вместо этого приложение каждый раз уходит в фоновый режим и ОС вызывает делегат applicationDidEnterBackground. В этот момент нам рекомендовано сохранить состояние приложения ибо после ухода в фон никто нам уже ничего не гарантирует. Приложение может быть вызывано обратно в интерактивный режим, оно может быть убито явно пользователем из таск панели(причем именно убито с использованием kill) и никаких сообщений не получит, оно может быть убито системой от нехватки памяти, устройство может быть перезагружено итп итд.
Самое важное во всем этом - нам говорят только о том, что приложение больше не активно. Больше нам ни о чем не скажут (ну почти ни о чем)
- Если приложение не было убито/выгружено, то при следующей попытке пользователя его запустить (как из SpringBoard, так и из таск панели) будет вызыван делегат applicationWillEnterForeground.
И вот здесь зарыта собака всего этого поста, а также соль многозадачности iOS - в этом делегате нужно не восстанавливать состояние, которое мы сохранили при вызове, а выполнять ОТКАТ всего того что мы насохраняли в applicationDidEnterBackground!
Объясняю почему:
- приложение всё еще активно, если мы явно ничего не поубивали на уходе в бэкграунд, то все данные в памяти - можно продолжать работать
- большинство приложений под старые версии iOS проектировались и разрабатывались именно с таким учетом, что их запустят, поработают и выйдут из них. Соответственно мало кто заботился о том, чтобы делать загрузку и переинициализацию в произвольный момент времени.
Если же мы начнем загружать данные в applicationWillEnterForeground, то можем столкнуться с необходимостью серьезной доработки кода, подчистке всего того, что не было сделано в старой версии (release, dealloc итп).
Так что выгодно и рекомендовано apple просто убивать сохраненное состояние и продолжать работать.
Если же приложение после ухода в фон было убито, то сохраненное в файле, локальную БД или куда-то еще не денется и штатным образом подхватится при рестарте.
Лично я убил немало так часов, чтобы осознать и осмыслить то, что вскользь описано в официальной документации. Надеюсь, этот пост поможет вам не совершить эту ошибку.
Подписаться на:
Комментарии к сообщению (Atom)
Комментариев нет:
Отправить комментарий