С выходом
Swift 6 разработчики получили строгие гарантии защиты от состояний гонки (data-race safety) в многопоточном коде. Однако эти гарантии принесли и новые сложности - система стала предъявлять требования даже к тому коду, который выполняется последовательно. В новом видении команда
Swift Evolution предлагает сделать модель безопасности более гибкой и дружелюбной, особенно для однопоточных приложений и плавной миграции.
Суть проблемы - безопасность там, где угрозы нет:
Текущая модель
Swift 6 по умолчанию предполагает, что любой код может выполняться в нескольких потоках одновременно. Это приводит к избыточным требованиям в сценариях, где реальной многопоточности нет.
// Пример ложного срабатывания
class AppSettings {
static let current = AppSettings() // Ошибка: небезопасно для параллельного доступа
}
Хотя если все приложение работает в основном потоке, состояние гонки здесь невозможно.
Новый подход - контекстные умолчания:
Основная идея - позволить системе различать контекст выполнения. Для модулей приложений и скриптов предлагается устанавливать изоляцию к
@MainActor по умолчанию, отражая их фактическое однопоточное поведение.
// Будущее: умолчание для модуля приложения
// module.moduleconfig: default-isolation = main-actor
class DataCache {
static let shared = DataCache() // Теперь корректно
var items: [String] = []
}
class ViewModel { // Неявно @MainActor
func load() {
DataCache.shared.items.append("data") // Работает без аннотаций
}
}
Изолированные реализации протоколов:
Сейчас тип, привязанный к актору, не может корректно реализовать обычный протокол - его методы требуют доступа к изолированным свойствам. Решение - изолированные соответствия, позволяющие использовать протокол только в правильном контексте.
protocol Serializable {
func serialize() -> Data
}
@MainActor
class UserProfile: Serializable {
private var data: [String: Any] = [:]
// Изолированная реализация протокола
func serialize() -> Data {
return try! JSONSerialization.data(withJSONObject: data)
}
}
Переосмысление async-поведения:
Поведение асинхронных функций также будет пересмотрено. Вместо автоматического переключения между потоками, они по умолчанию будут сохранять изоляцию вызывающего контекста, что сделает асинхронный код более предсказуемым.
Что это значит для разработчиков:
- Меньше рутинных аннотаций @MainActor в UI-коде.
- Упрощение миграции legacy-проектов.
- Более понятные ошибки компиляции.
- Сохранение строгой безопасности там, где она действительно нужна.
Вывод:
Эволюция многопоточности в
Swift движется к балансу между строгостью и практичностью. Система учится отличать действительно параллельный код от последовательного, применяя соответствующие требования. Это делает язык более доступным для начинающих и уменьшает порог входа для миграции существующих проектов, не жертвуя при этом безопасностью в сложных многопоточных сценариях.