Ответ
iOS предоставляет строго ограниченные механизмы для фонового выполнения задач, чтобы сохранять заряд батареи. Вот основные разрешённые способы:
1. Фоновые режимы (Background Modes)
Указываются в Info.plist (UIBackgroundModes). Каждый режим требует обоснования при ревью App Store.
<key>UIBackgroundModes</key>
<array>
<string>audio</string> <!-- Воспроизведение или запись аудио -->
<string>location</string> <!-- Получение обновлений геолокации -->
<string>fetch</string> <!-- Периодическое обновление контента -->
<string>processing</string> <!-- Завершение длительных задач -->
<string>remote-notification</string> <!-- Обработка пуш-уведомлений с контентом -->
</array>
2. Background Tasks Framework (iOS 13+) Предпочтительный современный API для коротких фоновых задач (например, синхронизация, очистка кэша).
// 1. Запросить идентификатор задачи у системы
var backgroundTaskID: UIBackgroundTaskIdentifier?
backgroundTaskID = UIApplication.shared.beginBackgroundTask(
withName: "Network Sync") {
// Этот блок вызовется, если время истекло. Необходима быстрая очистка.
if let taskID = backgroundTaskID {
UIApplication.shared.endBackgroundTask(taskID)
backgroundTaskID = .invalid
}
}
// 2. Выполнить асинхронную задачу (например, сетевой запрос)
DispatchQueue.global().async {
// Ваша фоновая работа
performSync()
// 3. ЯВНО завершить задачу по её окончании
DispatchQueue.main.async {
if let taskID = backgroundTaskID {
UIApplication.shared.endBackgroundTask(taskID)
backgroundTaskID = .invalid
}
}
}
3. Background Fetch Система сама предоставляет приложению периодическое время для предварительной загрузки данных.
// В AppDelegate:
func application(_ application: UIApplication,
performFetchWithCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
fetchNewData { newData in
if newData {
completionHandler(.newData)
} else {
completionHandler(.noData)
}
}
}
// Также нужно установить интервал (реальный интервал определяет система):
UIApplication.shared.setMinimumBackgroundFetchInterval(UIApplication.backgroundFetchIntervalMinimum)
4. Push-уведомления с контентом (Background Notifications)
Можно отправить пуш с content-available: 1, и система запустит приложение в фоне для обработки.
// В AppDelegate:
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// Обработать данные из пуша
completionHandler(.newData)
}
Ключевые ограничения:
- Время выполнения: Для
beginBackgroundTaskобычно даётся ~30 секунд. Для специальных режимов (аудио, локация) — больше. - Предсказуемость: Система решает, когда и как часто предоставлять фоновое время.
- Энергоэффективность: Чрезмерная фоновая активность приведёт к низкой оценке в Energy Impact в Instruments и возможному отказу в публикации.