Site icon AppTractor

Что нового в Swift 6.4 после WWDC26

Swift 6.4 включает в себя ряд улучшений языка и дополнений к стандартной библиотеке, которые делают повседневный код более чистым и выразительным. В этой статье рассматриваются наиболее заметные изменения, представленные на WWDC26.

Упрощенная доступность платформы с помощью anyAppleOS

Поскольку Apple унифицировала номера версий ОС на всех платформах, Swift 6.4 делает следующий шаг, позволяя объединить повторяющиеся атрибуты доступности в один токен anyAppleOS.

// Before
@available(macOS 27, iOS 27, watchOS 27, tvOS 27, visionOS 27, *)
func showStatus() { ... }

// After
@available(anyAppleOS 27, *)
func showStatus() { ... }

Когда требуется выделить какую-либо платформу, объедините anyAppleOS со специальным переопределением. Тот же токен работает внутри #if os(anyAppleOS) для условной компиляции.

Управление предупреждениями с помощью @diagnose

Бывают ситуации, когда необходимо вызвать устаревший API при планировании миграции или проверить критически важную функцию на предмет небезопасного использования, не допуская при этом распространения этих проблем на остальную часть проекта. Новый атрибут @diagnose обрабатывает оба случая.

@diagnose(DeprecatedDeclaration, as: ignored, reason: "Migrating incrementally")
func makeApolloMission() -> Mission {
    CrewedMission(rocket: makeSaturnIRocket(), ...)
}

Вы можете подавлять, переводить в состояние предупреждения или повышать до ошибки каждое объявление отдельно. Это точный инструмент, а не флаг, действующий в масштабе всего проекта.

Селекторы модулей для разрешения неоднозначности

Когда два импортированных модуля экспортируют одно и то же имя, Swift пытается разрешить конфликт через точечную нотацию. Но этот подход ломается, если в самом модуле есть тип с таким же именем, как у модуля. Новый синтаксис выбора модуля через :: гарантирует, что левая часть всегда будет трактоваться как модуль, а не как тип.

import SwiftUI
import Charts

let body = SwiftUI::View.self      // SwiftUI's View protocol
let chart = Charts::View.self      // Charts' View type

Селекторы модулей также работают с именами методов. Это полезно, когда тип наследует одноимённые методы из расширений, объявленных в разных модулях.

user.DatabaseKit::delete()   // removes from local store
user.CloudSync::delete()     // removes from remote

Это особенно полезно в сгенерированном коде, например в раскрытиях макросов, где вы не контролируете, что ещё импортировано в проект.

Более удобная работа с Sendable и конкурентностью

В Swift 6.4 исправили несколько небольших неудобств, связанных с конкурентностью. Раньше weak var свойств вынуждало использовать @unchecked Sendable; теперь его можно записать как weak let, и такая запись проходит обычную проверку Sendable без небезопасного выстраивания обходного пути.

final class Spacecraft: Sendable {
    weak let dockedAt: SpaceStation?
}

Когда класс должен явно отказаться от соответствия Sendable, это можно указать с помощью ~Sendable, вместо того чтобы оставлять это поведение неявным.

class Mission: ~Sendable { ... }
class CrewedMission: Mission, @unchecked Sendable { ... }

Вызов async-функций из блока defer теперь тоже разрешён. Это убирает ограничение, из-за которого раньше часто приходилось писать неудобные обходные решения.

let uploadTask = Task {
    try await storage.upload(file)
}

defer {
    await logger.flush()
}

try await uploadTask.value

Более доступные инициализаторы для участников

Если структура содержит одновременно internal— и private-свойства, Swift теперь генерирует два почленных инициализатора: один включает приватные свойства и доступен только внутри файла, а второй не включает их и доступен во всём модуле. Раньше второй инициализатор приходилось писать вручную.

struct Briefing {
    internal var topic: String
    internal var scheduledAt: Date
    private  var attendees: [Person] = []
    // Swift now generates both a private full init and an internal partial init
}

Дополнения в стандартной библиотеке

Защита от отмены задачи

Некоторые операции должны завершиться даже после отмены задачи, например сброс буфера файла, чтобы избежать повреждения данных. withTaskCancellationShield оборачивает участок кода, внутри которого Task.isCancelled всегда возвращает false.

extension EmergencyTransponder {
    func sendSOS() {
        withTaskCancellationShield {
            radio.send(makeSOSPacket())
        }
    }
}

Держите экранированную область короткой и сосредоточьтесь на откате или завершении работы.

mapKeyedValues ​​в словаре

Существующий mapValues ​​предоставляет только значение в замыкании преобразования. Новый mapKeyedValues ​​передает как ключ, так и значение.

let displayNames = missions.mapKeyedValues { mission, window in
    makeDisplayName(for: mission, in: window)
}

Новый тип FilePath

В стандартную библиотеку добавлен тип FilePath, перенесенный из Swift System. Он корректно обрабатывает различия в представлении путей между платформами и последовательно анализирует компоненты, устраняя распространенный источник скрытых ошибок в кроссплатформенном коде.

var path: FilePath = "/Users/khoa/Documents"
path.components.append("Projects")
path.components.append("app")
print(path.components)
// [ "Users", "khoa", "Documents", "Projects", "app" ]

Что еще почитать

Exit mobile version