Ответ
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 и возможному отказу в публикации.
Ответ 18+ 🔞
А, слушай, смотри, этот ваш 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+) Это типа цивилизованный способ, мол, «дайте мне, пожалуйста, 30 секунд, я быстро». Но система, сука, может и не дать, или дать, а потом отобрать. Главное — не забыть сказать «спасибо, я всё», а то прибьёт.
// 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. Пуш-уведомления с content-available
Хитрая жопа, блядь. Отправляешь пуш с флажком content-available: 1, и iOS такой: «О, ну ладно, запущу тебя ненадолго в фоне, обработай это».
// Опять в AppDelegate:
func application(_ application: UIApplication,
didReceiveRemoteNotification userInfo: [AnyHashable: Any],
fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// Тут что-то делаешь с данными из пуша
completionHandler(.newData) // И обязательно кричишь, что сделал
}
А теперь, сука, самое важное — ограничения:
- Время: Обычно дают секунд 30, не больше. Как на перекур. Для аудио или гео — побольше, но это спецпропуск.
- Предсказуемость: Это не ты решаешь, когда работать. Это система решает, дать тебе время или послать нахуй.
- Батарея: Если будешь слишком активно ебашить в фоне, Instruments покажет тебе красный Energy Impact, а ребята из App Store скажут: «Иди нахуй со своим приложением, оно батарею жрёт».