Что нового в Swift 6 и особенности миграции
Swift 6 — это новый крупный релиз языка программирования от Apple, анонсированный на WWDC 2024. Если вы следили за эволюцией Swift, то наверняка заметили, что многие значимые возможности, которые появлялись в последних версиях, были частью дорожной карты именно к этому релизу. Например, введение асинхронного программирования с async/await в Swift 5.5 было не просто отдельной функцией, а элементом большого плана по подготовке к Swift 6. Эта версия языка отличается от предыдущих обновлений тем, что в ней меньше новых ярких функций, но гораздо больше внимания уделено безопасности, надежности и производительности кода. Главный фокус Swift 6 — создание фантастического опыта разработки программного обеспечения. В Swift 6 важно понимать не только что изменилось, но и почему эти изменения были внедрены. Команда Swift опубликовала свои области фокуса на 2023 год и подробную дорожную карту к версии 6, что дает четкое представление о видении будущего языка. Каждый релиз Swift 5.x играл свою роль в постепенном движении к этой цели. Что касается сроков, Swift 6 уже здесь — он стал официально доступен вместе с выпуском Xcode 16. Это значит, что сейчас самое время начать планировать миграцию своих проектов. Ключевые изменения и общее направление развитияУстранение гонок данных стало приоритетом для команды Swift. После миграции проектов на новую версию вы заметите множество предупреждений, связанных с протоколом Sendable и правильным использованием многопоточности. Эти предупреждения указывают на потенциальные проблемы с потокобезопасностью. Многие непредсказуемые сбои в приложениях связаны именно с гонками данных, и они могут исчезнуть после успешной миграции.Жёсткая проверка многопоточности — второй столп нового релиза. Когда вы переключитесь на режим языка Swift 6, вы увидите много предупреждений и ошибок в проекте. Не паникуйте — это нормально. Правила стали строже, чтобы сделать параллельный код безопаснее и помочь вам правильно применять концепции конкурентности Swift. В результате применения этих подходов мы получаем более предсказуемое выполнение кода. Код станет менее подвержен неожиданным проблемам во время выполнения. Если вы раньше боролись с малопонятными ошибками EXC_BAD_ACCESS, то после миграции на Swift 6 эта проблема может уйти навсегда. Swift 6 — это не столько о новых ярких функциях, сколько о совершенствовании существующих возможностей и повышении надёжности. Если функции вроде async/await в Swift 5.5 были захватывающими новинками, то Swift 6 больше сосредоточен на обеспечении более строгой проверки конкурентности. Усиленная поддержка многопоточности не нова сама по себе, но предлагает новый уровень защиты. Предыдущие версии языка подготовили почву, но теперь мы видим более строгую проверку с меньшим количеством ложных срабатываний. Проверки безопасности от гонок данных, которые раньше были доступны в виде предупреждений через флаг компилятора -strict-concurrency=complete , теперь будут приводить к ошибкам компиляции при диагностике потенциальных гонок данных. Вместе с этим Swift 6 представил новую библиотеку синхронизации (Synchronization). Хотя она не будет использоваться большинством разработчиков, эта библиотека предлагает низкоуровневые API для конкурентности, включая атомарные операции и новый API для мьютексов.Ещё одно значительное улучшение — типизированные исключения (typed throws). Они делают код более предсказуемым, поскольку сокращают количество типов ошибок, к которым нужно быть готовым на уровне реализации. Например:
ValidationError . На уровне реализации нам нужно заботиться только о случаях ошибок этого типа, что упрощает код и делает его более понятным.Большим шагом вперёд стала возможность управлять расползанием зависимостей с помощью модификаторов уровня доступа для импорта. Теперь вы можете применять такие модификаторы, как public, private и internal, не только к классам, методам и свойствам, но и к импортам пакетов:
Что такое HStack, VStack с точки зрения swift Какие особенности сетевой инфраструктуры при миграции приложений в облако? Создалось большое количество таблиц при миграции, которых я не создавал. И ошибка при самой миграции Попытка миграции на SQL Server. Что делать с датами? Основные улучшения языкаSwift 6 вносит ряд улучшений в язык, которые выходят за рамки чисто технических изменений. Эти улучшения направлены на создание более безопасного, предсказуемого и производительного кода. Улучшения системы конкурентностиВ Swift 6 модель многопоточности претерпела серьезные изменения. Хотя сама система async/await существовала и раньше, теперь она стала более строгой и надежной. Система типов теперь обеспечивает безопасность при передаче данных между потоками через концепцию Sendable .Протокол Sendable служит своего рода маркером, который гарантирует, что определенный тип безопасен для передачи между потоками. В Swift 6 компилятор гораздо строже относится к проверке соответствия этому протоколу. Это может проявляться в виде большого количества предупреждений при первой миграции проекта:
UserSettings не соответствует протоколу Sendable , компилятор выдаст ошибку при попытке использовать UserProfile в асинхронном контексте. Помимо более строгой типизации, Swift 6 вводит улучшенную поддержку глобальных акторов. Глобальные акторы, такие как @MainActor , теперь имеют более строгие правила изоляции, что помогает избежать ошибок, связанных с одновременным доступом к данным из разных потоков.Типизированные исключенияТипизированные исключения — еще одно важное улучшение в Swift 6. До этой версии все функции, которые могли выбрасывать исключения, использовали ключевое слово throws без указания конкретного типа исключения. Это означало, что вызывающий код должен был быть готов к обработке любого возможного типа ошибки. В Swift 6 можно указать конкретный тип исключения:
Улучшения в работе с зависимостямиSwift 6 вносит изменения в работу с зависимостями через модификаторы доступа для импорта. Теперь вы можете контролировать видимость импортированных модулей:
Функциональные улучшенияВ Swift 6 также появилось несколько новых функциональных методов, которые упрощают работу с коллекциями. Например, новый метод count(where:) , который позволяет подсчитать элементы, удовлетворяющие определенному условию:
contains(where:) :
contains(where:) останавливается сразу после нахождения первого элемента, удовлетворяющего условию, что делает его более эффективным для таких проверок.Новая библиотека синхронизацииSwift 6 представляет новую библиотеку Synchronization , которая предоставляет низкоуровневые API для конкурентности. Эта библиотека включает атомарные операции и новый API для мьютексов:
Улучшения в системе типовSwift 6 также вносит ряд улучшений в систему типов. Например, теперь есть лучшая поддержка для работы с экзистенциальными типами (типы, использующие ключевое слово any ). В Swift 6 компилятор будет требовать явного использования any перед протоколами, используемыми как типы:
any явно указывает на то, что мы имеем дело с экзистенциальным типом, который имеет определенные последствия для производительности.Макросы и метапрограммированиеЕщё одно значительное улучшение в Swift 6 — расширенная поддержка макросов. Макросы в Swift — это мощный инструмент для метапрограммирования, позволяющий автоматизировать повторяющиеся шаблоны кода. В Swift 6 система макросов стала более надежной и гибкой. Например, вы можете использовать макрос @Observable для автоматической генерации кода, связанного с наблюдаемыми свойствами:
Улучшения производительностиSwift 6 также включает в себя множество низкоуровневых оптимизаций, направленных на улучшение производительности. Компилятор теперь лучше справляется с анализом и оптимизацией кода, что может привести к более быстрому выполнению и меньшему потреблению памяти. Одним из таких улучшений является более эффективная работа с протоколами и экзистенциальными типами. В предыдущих версиях Swift использование протоколов как типов (экзистенциальных типов) могло привести к дополнительным затратам на производительность из-за необходимости использования динамической диспетчеризации. В Swift 6 компилятор стал умнее в определении случаев, когда можно применить статическую диспетчеризацию, что улучшает производительность. Улучшения в работе со строкамиSwift 6 вводит некоторые улучшения в работе со строками. Например, появились новые методы для более эффективного поиска и манипуляции подстроками. Вот пример использования некоторых из этих улучшений:
Расширенная поддержка результирующих типовSwift 6 расширяет возможности работы с результирующими типами (Result types), которые были введены в Swift 5. Теперь имеется более тесная интеграция между результирующими типами и системой обработки ошибок:
Улучшения в системе модулейSwift 6 также улучшает систему модулей, что особенно важно для крупных проектов с множеством зависимостей. Теперь она лучше справляется с циклическими зависимостями и предоставляет более информативные сообщения об ошибках при проблемах с импортом. Эти улучшения, хоть и не такие заметные как новые конструкции языка, могут существенно упростить разработку и сопровождение больших проектов, состоящих из множества модулей и пакетов. Миграция проектовВремя, затраченное на миграцию проектов на Swift 6, зависит от типа и размера вашего проекта. Независимо от масштаба, я рекомендую постепенный подход к внедрению, чтобы изолировать изменения и создавать пул-реквесты, которые будут достаточно компактными для обзора. Процесс миграции включает несколько ключевых шагов, которые одинаково применимы как к Swift-пакетам, так и к проектам Xcode: Определение изолированной части проектаПервый шаг миграции — выбор изолированной части кода. При больших рефакторингах, а миграция на Swift 6 определенно может быть масштабным рефакторингом, критически важно начинать с изолированных участков кода. Под изолированным кодом я подразумеваю код, который можно скомпилировать отдельно от остальной части проекта — это могут быть отдельные таргеты или независимые модули. Если возможно, начните с небольшого расширения приложения с меньшим количеством файлов. Это позволит вам познакомиться с процессом миграции на примере ограниченного объема кода, прежде чем переходить к более сложным частям проекта. Последовательное включение предстоящих функций Swift 6Следующим шагом будет поочередное включение предстоящих языковых функций. Вы можете сделать это, перейдя в настройки сборки (build settings) вашего проекта и выполнив поиск по запросу "Upcoming features". Отфильтрованный список настроек сборки покажет доступные предстоящие языковые функции и настройку строгой проверки конкурентности. Я советую сосредоточиться на настройках сборки, содержащих переменную $(SWIFT_UPCOMING_FEATURE_6_0) , поскольку они напрямую связаны со Swift 6. Эти функции также будут автоматически включены, когда вы измените версию языка проекта на шесть.После включения одной из предстоящих функций вы, вероятно, увидите новые предупреждения. Некоторые из них превратятся в ошибки, когда вы обновите версию языка, поэтому постарайтесь устранить как можно больше из них. После завершения откройте пул-реквест только с этими изменениями, прежде чем переходить к следующей предстоящей функции. Для Swift-пакетов вы можете включить предстоящие функции следующим образом:
Включение строгой проверки конкурентностиВключение предстоящих функций по одной подготавливает ваш проект к строгой проверке конкурентности. Настройка строгой проверки конкурентности контролирует уровень принуждения Sendable и проверки изоляции акторов, выполняемой компилятором Swift.Существует три уровня на выбор:
Каждый шаг приводит к более строгой проверке и потенциально к большему количеству предупреждений. Не торопитесь и адаптируйте каждый уровень по отдельности. После устранения предупреждений для каждого уровня можно открыть пул-реквест и перейти к следующему уровню. Если вы используете Swift-пакеты, вы можете изменить уровень строгости конкурентности следующим образом:
Изменение версии языка Swift на Swift 6Заключительный этап миграции требует изменения версии языка Swift на Swift 6. Перейдите в настройки сборки и выполните поиск по запросу "Swift Language Version". После включения вы можете все еще столкнуться с новыми предупреждениями и ошибками, но благодаря постепенным шагам миграции вы, вероятно, уже устранили множество предупреждений. Для пакетов вы можете установить swift-tools-version на 6.0, чтобы включить режим языка Swift 6 для всех целевых объектов:
Package.swift . Чтобы обновить конкретный целевой пакет до старой версии языка, вам нужно использовать следующие настройки Swift:
Рекомендации для постепенной миграцииКогда я мигрировал SDK WeTransfer, состоящий из более чем 20 пакетов, я выработал несколько практических рекомендаций, которые могут быть полезны: 1. Начните с тестовых целей: тесты часто проще мигрировать, и они дают вам хорошее представление о том, с какими проблемами вы можете столкнуться в основном коде. 2. Используйте ветвление для изоляции изменений: создавайте отдельные ветки для каждого шага миграции, чтобы было легче отследить изменения и в случае необходимости откатить их. 3. Обновляйте зависимости постепенно: если ваш проект зависит от сторонних библиотек, проверьте, совместимы ли они с Swift 6, и при необходимости обновите их заранее. 4. Регулярно тестируйте: после каждого шага убедитесь, что ваш код по-прежнему компилируется и проходит различные типы испытаний, включая модульные тесты, интеграционные тесты и ручное тестирование для критически важных компонентов. 5. Документируйте изменения: ведение лога изменений поможет вашей команде понять, что было изменено и почему. Это особенно важно для более крупных проектов с несколькими участниками. Миграция — это не гонка. Даже если некоторые зависимости уже перешли на Swift 6, ваш проект по-прежнему может использовать Swift 5 без каких-либо проблем. Вы можете мигрировать, когда будете готовы и у вас будет время для тщательного тестирования. Решение распространенных проблем при миграцииПри миграции на Swift 6 вы, скорее всего, столкнётесь с рядом типичных проблем. Я расскажу о наиболее частых из них и способах их решения. Проблемы с протоколом SendableОдна из самых распространенных проблем — несоответствие типов протоколу Sendable . Swift 6 требует, чтобы типы, передаваемые между разными потоками исполнения, соответствовали этому протоколу. Вот несколько подходов к решению:1. Добавление явного соответствия Sendable:
Если у вас есть класс с переменными свойствами, вам придется использовать средства синхронизации:
Проблемы с изоляцией акторовВторая распространённая группа проблем связана с нарушением изоляции акторов: 1. Неправильный доступ к свойствам актора:
Автоматизация миграции с помощью скриптовДля больших проектов можно автоматизировать некоторые аспекты миграции. Вот простой bash-скрипт, который поможет находить потенциальные проблемы с Sendable:
Инструменты и флаги компилятораПри миграции стоит знать о полезных флагах компилятора, которые помогут выявить проблемы: 1. -warn-concurrency: этот флаг заставляет компилятор выдавать предупреждения о потенциальных проблемах с конкурентностью. 2. -strict-concurrency=complete: включает полную проверку соблюдения правил конкурентности во всем проекте. 3. -allow-compiler-errors: позволяет продолжить компиляцию, несмотря на ошибки, что помогает видеть все проблемы сразу, а не только первую из них. Для проектов Xcode эти флаги можно добавить в "Other Swift Flags" в настройках сборки:
Стратегия миграции для корпоративных проектовМиграция большого корпоративного проекта требует особого подхода: 1. Формирование команды миграции: выделите небольшую группу разработчиков (2-3 человека), которые будут заниматься миграцией. Это обеспечит согласованный подход. 2. Приоритизация компонентов: определите порядок миграции компонентов. Обычно стоит начинать с базовых библиотек и постепенно двигаться к интерфейсным компонентам. 3. Создание гитхаб-проекта для отслеживания: организуйте доску в GitHub Projects или аналогичном инструменте для отслеживания прогресса миграции по каждому компоненту. 4. Фиксация еженедельных целей: установите реалистичные еженедельные цели — например, мигрировать 2-3 компонента в неделю. 5. Регулярные обзоры кода: проводите регулярные обзоры изменений, связанных с миграцией, чтобы избежать регрессий. 6. Дублирование тестирования: запускайте тесты как в режиме Swift 5, так и в режиме Swift 6, пока миграция не будет завершена. 7. Постепенное обновление документации: по мере миграции обновляйте документацию для отражения новых подходов к работе с конкурентностью. 8. Обучение команды: проводите внутренние воркшопы, чтобы все члены команды понимали изменения и новые практики программирования. Обратная совместимость и работа со сторонними библиотекамиОдин из важных аспектов миграции — обратная совместимость. Swift 6 был разработан с учётом этого фактора, но всё же могут возникнуть проблемы: 1. Устаревшие зависимости: некоторые библиотеки могут не обновляться до Swift 6. В этом случае у вас есть несколько опций: - Временно использовать режим Swift 5 для этих зависимостей. - Форкнуть и обновить библиотеку самостоятельно. - Найти альтернативную библиотеку, которая поддерживает Swift 6. 2. Частичная миграция: вы можете мигрировать свой проект частично, используя разные версии языка для разных модулей:
Примеры кода и практические решенияПереход на Swift 6 означает не только изменение настроек проекта, но и адаптацию вашего кода к новым парадигмам. В этом разделе мы рассмотрим конкретные примеры, показывающие, как код меняется при миграции, и предложим практические решения для типичных сценариев. До и после: сравнение синтаксисаРассмотрим несколько примеров кода "до и после" миграции на Swift 6, которые демонстрируют ключевые изменения. Обработка ошибок с типизированными исключениямиSwift 5:
Использование акторов и протокола SendableSwift 5:
Зависимости с модификаторами доступаSwift 5:
Оптимизация сетевого взаимодействия с новыми APISwift 6 позволяет переписать сетевой код более элегантно, используя async/await и типизированные исключения:
1. Код становится более линейным и понятным. 2. Типизированные исключения делают контракт функции более явным. 3. Исключается возможность гонок данных. 4. Легко выполнять задачи на главном потоке с помощью MainActor. Рефакторинг архитектуры под новую парадигму конкурентностиРассмотрим, как можно рефакторить типичный MVVM-паттерн для использования с преимуществами Swift 6:
1. User типизирован как Sendable , что делает его безопасным для передачи между потоками.2. UserService реализован как актор, обеспечивающий изоляцию состояния.3. UserViewModel помечен как @MainActor , гарантируя, что все его методы выполняются в главном потоке.4. Асинхронное программирование с async/await делает код более читаемым.Случаи, когда миграция может негативно повлиять на производительностьХотя Swift 6 в целом улучшает производительность, есть случаи, когда неосторожное использование новых возможностей может привести к обратному эффекту: Излишнее использование акторовАкторы вносят небольшие накладные расходы из-за асинхронного доступа. Создание слишком большого количества акторов может привести к снижению производительности:
Неоптимальная работа с коллекциямиПри миграции на Swift 6 легко переусердствовать с асинхронностью, заставляя асинхронно выполняться операции, которые могли бы выполняться синхронно:
Оптимизация производительностиВот несколько советов по оптимизации производительности при миграции на Swift 6: Используйте изолированные функции вместо акторов для простых случаев
Минимизируйте границы асинхронностиПереключение между синхронным и асинхронным выполнением имеет стоимость. Старайтесь объединять асинхронные операции вместо их разделения:
Используйте локализацию для акторовЕсли вам нужен только локальный доступ к актору в функции, создавайте его внутри функции:
Что использовать: Swift или Objective-C? Подскажите, какой выбрать powerbank что бы можно было заряжать acer swift 3! 2. Какую структуру имеет объект динамического класса, в чем заключаются его особенности? 3. Объясните Особенности Исполн Что такое Особенности Адресной Арифметики? Что такое "миграции" и почему нельзя просто делать дамп БД ? Что нового в 7.x Что нового в 8.5.3 Что нового в EJB 2.0 ? Windows 8 что нового? Что нового в ECMAScript 6 Что нового в FPC-3.0.0? Java 8, что нового? |