Ответ
Для последовательного выполнения асинхронных задач в Swift используются механизмы, гарантирующие, что следующая задача начнется только после завершения предыдущей.
Основные подходы:
1. Serial DispatchQueue Наиболее простой способ для задач, не возвращающих результат.
let serialQueue = DispatchQueue(label: "com.example.serialQueue")
serialQueue.async {
print("Задача 1 начата")
// Долгая операция...
print("Задача 1 завершена")
}
serialQueue.async {
print("Задача 2 начата") // Начнется строго после Задачи 1
// Долгая операция...
print("Задача 2 завершена")
}
serialQueue.async {
print("Задача 3 начата") // Начнется строго после Задачи 2
// Долгая операция...
print("Задача 3 завершена")
}
2. OperationQueue с maxConcurrentOperationCount = 1 Позволяет добавлять зависимости между задачами.
let serialOperationQueue = OperationQueue()
serialOperationQueue.maxConcurrentOperationCount = 1
let op1 = BlockOperation { print("Задача 1") }
let op2 = BlockOperation { print("Задача 2") }
let op3 = BlockOperation { print("Задача 3") }
// Можно явно задать зависимости, даже при serial очереди
// op2.addDependency(op1)
// op3.addDependency(op2)
serialOperationQueue.addOperations([op1, op2, op3], waitUntilFinished: false)
3. Async/Await с циклом Современный способ для задач, возвращающих результат.
func performTasksSerially() async {
let tasks: [() async -> Void] = [
{ await longRunningTask(id: 1) },
{ await longRunningTask(id: 2) },
{ await longRunningTask(id: 3) }
]
for task in tasks {
await task() // Каждая задача ожидает завершения предыдущей
}
}
func longRunningTask(id: Int) async {
print("Задача (id) начата")
try? await Task.sleep(nanoseconds: 1_000_000_000) // Имитация работы
print("Задача (id) завершена")
}
Ключевой момент: serialQueue.async не блокирует вызывающий поток, но задачи внутри очереди выполняются строго по порядку.