Как включить режим Swift 6 для ваших Xcode-проектов и SwiftPM-модулей уже сегодня. А также каков опыт миграции.
Автор: Джихат Гюндюз
Дата публикации: 19 апреля 2023 г.
Время чтения: 5 минут
Что такое "режим Swift 6”?
Swift 6 не будет выпущен в 2023 году, это было ясно сказано Дагом Грегором из Рабочей группы по Swift Language. Но вы знали, что Apple уже добавила элементы Swift 6 в 5.8? Да, это правда. Некоторые компоненты Swift, внесенные вместе с Xcode 14.3 несколько недель назад, по умолчанию выключены. Они будут включены, как только будет выпущен Swift 6, что может занять еще год или больше.
Эти элементы вносят некоторые изменения в Swift, например, переименовывают известные API, корректируют их поведение или добавляют в компилятор новые проверки безопасности. Но в какой-то момент все они будут включены, чтобы улучшить наши кодовые базы. И нам придется обновлять наши проекты, чтобы соответствовать этим изменениям.
Я подумал: хорошая идея - включить все функции в моих проектах, чтобы узнать, есть ли какие-то критические изменения кодовой базы, о которых я должен знать. И, конечно, я также мог бы поюзать некоторые новые функции. Одна из них - BareSlashRegexLiterals, делающая синтаксис литерала регулярных выражений /.../ доступным для краткой инициализации Regex.
К счастью, с Swift 5.8 теперь есть единый способ включения этих параметров: мы просто должны передать -enable-upcoming-feature в Swift, указав его в OTHER_SWIFT_FLAGS в настройках сборки нашего проекта в Xcode. Но нам также нужно знать, какие из функций доступны, а я не смог найти ничего с верным описанием (пока что). Рекомендация, вводящая данный единый параметр, содержит вот такой список, но в дальнейшем он не был обновлен с позже добавленными новыми параметрами, например, из SE-0384. Итак, где сейчас мы можем получить точный список всех поддерживаемых параметров?
✨ ОБНОВЛЕНИЕ: Теперь вы можете фильтровать по предстоящим флагам непосредственно на Swift.org.
Swift - язык с открытым исходным кодом, поэтому самым подходящим местом кажется репозиторий Swift на GitHub! Он включает в себя файл Features.def, который содержит записи (ссылка на ветку release/5.8), названные UPCOMING_FEATURE, включающие и номер соответствующего предложения Swift Evolution и версию Swift, в которую они будут включены:
UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
UPCOMING_FEATURE(ForwardTrailingClosures, 286, 6)
UPCOMING_FEATURE(BareSlashRegexLiterals, 354, 6)
UPCOMING_FEATURE(ExistentialAny, 335, 6)
Опции с кратким описанием того, что они делают:
- ConciseMagicFile: Изменяет #file, чтобы означать #fileID вместо #filePath.
- ForwardTrailingClosures: Удаляет правило соответствия обратного сканирования.
- ExistentialAny: Требует any для ЭКЗИСТЕНЦИАЛЬНЫХ типов.
- BareSlashRegexLiterals: Делает доступным синтаксис литерала регулярного выражения /…/.
По всей видимости, по какой-то причине две опции там не перечислены (я изучаю этот вопрос):
- StrictConcurrency: Выполнение полной проверки параллелизма.
- ImplicitOpenExistentials: Выполняет неявное открытие в дополнительных случаях.
Больше опций будет добавлено в более поздних версиях, например,
ImportObjcForwardDeclarations.
Для дополнительной проверки своего кода на соответствующую поддержку параллелизма, я решил также передавать -warn-concurrency (на самом деле это должно быть то же самое, что и StrictConcurrency, если это на самом деле работает) и -enable-actor-data-race-checks.
Перенос моего проекта:
Если вы тоже, хотите включить все опции из 5.8 в свой проект, скопируйте (⌘C) следующий текстовый блок, затем перейдите на вкладку "Build Settings" вашего проекта в Xcode, найдите "Other Swift Flags", выберите эту опцию в редакторе и вставьте (⌘V) блок:
//:configuration = Debug
OTHER_SWIFT_FLAGS = -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature ImplicitOpenExistentials -enable-upcoming-feature StrictConcurrency -warn-concurrency -enable-actor-data-race-checks
//:configuration = Release
OTHER_SWIFT_FLAGS = -enable-upcoming-feature BareSlashRegexLiterals -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature ExistentialAny -enable-upcoming-feature ForwardTrailingClosures -enable-upcoming-feature ImplicitOpenExistentials -enable-upcoming-feature StrictConcurrency -warn-concurrency -enable-actor-data-race-checks
//:completeSettings = some
OTHER_SWIFT_FLAGS
Если вы, как и я, используете приложение, модуль которого SwiftPM, или работаете над Swift-пакетом, вам дополнительно необходимо будет передать массив .enableUpcomingFeature для каждой цели через swiftSettings:
let swiftSettings: [SwiftSetting] = [
.enableUpcomingFeature("BareSlashRegexLiterals"),
.enableUpcomingFeature("ConciseMagicFile"),
.enableUpcomingFeature("ExistentialAny"),
.enableUpcomingFeature("ForwardTrailingClosures"),
.enableUpcomingFeature("ImplicitOpenExistentials"),
.enableUpcomingFeature("StrictConcurrency"),
.unsafeFlags(["-warn-concurrency", "-enable-actor-data-race-checks"]),
]
let package = Package(
// ...
targets: [
// ...
.target(
name: "MyTarget",
dependencies: [/* ... */],
swiftSettings: swiftSettings
),
// ...
]
Не забудьте в верхней части файла обновить версию инструментов до 5.8:
// swift-tools-version:5.8
.enableUpcomingFeature доступен только в Swift 5.8.
Все потому, что Swift не передает опции, указанные для целевой платформы вашего проекта, автоматически любым модулям, которые вы импортируете в свой проект. Это хорошая новость, т.к. пакеты Swift, которые вы можете включать в свой проект, не требуют каких-либо настроек, и вы все еще можете использовать данные элементы для своего собственного приложения. И наоборот: авторы пакетов могут включить эти элементы для своих проектов, не затрагивая код в проектах, в которые они будут включены.
После включения этих опций и построения проекта я столкнулся с четырьмя типами проблем:
1. Мне пришлось добавить ключевое слово any в нескольких местах - Xcode помог с исправлением с помощью Fix-It:
2. Я столкнулся с большим количеством ошибок для вью с модификатором .sheet. Указанные пары ошибок: "Не удалось определить универсальный параметр 'Content'" и "Отсутствует аргумент для параметра 'content' в вызове". Однако эти сообщения были не очень полезными, поэтому я сначала попытался заменить содержимое .sheet на просто Text-вью, но это не помогло. Поэтому я попробовал выключить опции одну за другой, и ошибки исчезли, когда я выключил ForwardTrailingClosures, и я оставил ее выключенной. Я надеюсь, что в будущих версиях Swift появятся лучшие сообщения об ошибках, чтобы в последствии их можно было исправлять. В конце концов спешить некуда. Я могу попробовать на Swift 5.9. Не было времени изучить вопрос.
3. Мне пришлось пометить свои некоторые функции, возвращающие TCA WithViewStore, атрибутом @MainActor, но здесь снова мне помог Xcode с Fix-It.
4. Во многих местах были показаны предупреждения: “Не отправляемый тип '...' передан в вызов основной, изолированной актором функции, не может пересечь границу актора". Поэтому я подвел эти типы под протокол Sendable (узнать о Sendable можно здесь).
Все остальное выглядело для моего приложения RemafoX с ~35 тысячами строк Swift-кода отлично работающим. Весь процесс занял менее 3 часов моего времени.
Мой проект теперь готов к будущему Swift 🎉, и я могу использовать новую функцию Регулярных выражений (let regex = /.@./). Кроме того, я не могу вставить новый код, который я должен буду позже перенести на Swift 6, т.к. сразу же получу ошибки. 💯
Что насчет вашего проекта? К каким будущим функциям вы хотите перейти?