Старый Swift-модуль импортирован с @preconcurrency: что изменится при проверке передачи его типов между конкурентными задачами?
@preconcurrency ослабляет статическую проверку конкурентности для деклараций импортированного модуля, который ещё не адаптирован к современным требованиям Swift Concurrency. В частности, компилятор может не сообщить об отсутствии Sendable или о проблемном пересечении границ изоляции.
Это не делает типы безопасными, не добавляет им соответствие Sendable и не вводит синхронизацию во время выполнения. Атрибут является временным механизмом совместимости при миграции.
Swift Concurrency появилась после большого количества существующего кода и библиотек, созданных до появления async/await, акторов и Sendable. Немедленное включение строгой проверки для всех таких модулей сделало бы миграцию крупных проектов практически непосильной.
@preconcurrency позволяет подключить старый модуль и временно уменьшить количество диагностик, пока его публичные типы и методы не будут проверены и размечены для конкурентного использования.
Предположим, старый модуль возвращает ссылочный объект с изменяемым состоянием. Такой объект передают из одной задачи в другую через границу изоляции, но модуль импортирован с @preconcurrency.
Компилятор может пропустить этот код, хотя две задачи потенциально обращаются к одному объекту одновременно. Если объект не защищён актором, очередью или другой синхронизацией, сохраняется риск гонки данных, повреждения состояния и недетерминированного поведения.
Главная опасность — принять отсутствие ошибки компиляции за доказательство безопасности. @preconcurrency скрывает часть проблем миграции, но не устраняет саму проблему.
При обычной строгой проверке Swift анализирует пересечение границ конкурентности: например, передачу значения в другую задачу или вызов метода с другого актора. Для этого используются сведения о Sendable, изоляции акторов и глобальных акторов.
При @preconcurrency import компилятор рассматривает объявления этого модуля как созданные до внедрения проверок конкурентности. Поэтому диагностика, связанная с такими объявлениями, может быть ослаблена или подавлена. Область действия относится к импортированным декларациям, а не ко всему коду приложения.
Атрибут не изменяет:
Sendable на уровне исполнения.Практически @preconcurrency следует применять как временную границу миграции. Нужно зафиксировать импортируемые типы, которые пересекают конкурентные границы, проверить их потокобезопасность, заменить небезопасные объекты на Sendable-значения или изолировать состояние актором, а затем убрать атрибут и вернуть строгую диагностику.
Приложение использует старую сетевую библиотеку, чьи модели являются изменяемыми классами. После перехода проекта на строгую проверку конкурентности сборка начинает выдавать множество диагностик, поэтому команду временно добавляет @preconcurrency к импорту.
Вариант оставить атрибут навсегда прост, но он скрывает новые ошибки на границе библиотеки. Вариант немедленно переписать всю библиотеку безопаснее, однако может быть слишком дорогим и остановить миграцию.
Разумное решение — временно сохранить атрибут, но разрешить передачу объектов библиотеки только через один изолированный адаптер. Адаптер сериализует доступ или преобразует результаты в неизменяемые Sendable-значения. После обновления или обёртывания библиотеки @preconcurrency удаляют и проверяют, что компилятор снова видит все потенциально небезопасные границы.
@preconcurrency соответствие Sendable для импортированного типа?Нет. Он меняет правила диагностики при использовании декларации, но не добавляет протоколу фактическое соответствие и не доказывает безопасность типа. Изменяемый класс остаётся изменяемым классом, поэтому его конкурентное использование всё ещё требует изоляции или собственной синхронизации.
@preconcurrency поведение программы во время выполнения?Нет. Это указание компилятору, а не runtime-механизм. Атрибут не ставит блокировки, не переключает выполнение на актор и не сериализует вызовы; он лишь позволяет пройти проверку кода, который иначе мог бы получить диагностику.
@preconcurrency?После проверки обновлённого модуля и всех его типов, пересекающих границы конкурентности. Если библиотека получила корректные Sendable-соответствия и annotations изоляции, атрибут обычно больше не нужен. Его удаление важно как контрольный этап: вновь появившиеся ошибки показывают места, где приложение всё ещё опиралось на скрытую компилятором проблему.