Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2026 Developer ToolsSwift

WWDC26 · 33 min · Developer Tools / Swift

What’s new in Swift

Join us for an update on Swift. Discover the latest language advancements, including updates for everyday ergonomics, improved concurrency, and safer high-performance code. Explore workflow and language interoperability improvements and updates in embedded Swift.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

  • 0:07 — Introduction
  • 0:44 — Everyday Language Improvements
  • 1:55 — anyAppleOS Availability
  • 3:02 — @diagnose Attribute
  • 3:52 — Module Selectors (::)
  • 5:59 — Library Updates
  • 6:16 — Standard Library
  • 7:31 — Swift Testing Updates
  • 9:29 — Subprocess 1.0
  • 10:14 — Foundation
  • 11:59 — Beyond Apple Platforms
  • 12:35 — Swift–C Interoperability (@C attribute)
  • 15:09 — Swift-Java
  • 16:03 — Editor support
  • 16:44 — WebAssembly (Wasm) & JavascriptKit
  • 18:08 — Embedded Swift
  • 19:59 — Performance Tuning
  • 21:29 — Optimizer Control: @inline(always) & @specialized
  • 24:29 — Ownership System & Noncopyable Types
  • 26:18 — Iterable Protocol & Borrow/Mutate Accessors
  • 28:57 — New Standard Library Types: UniqueBox, UniqueArray, Ref
  • 31:11 — The Future of Swift

Code shown on screen · 35 snippets

Better Swift Concurrency diagnostics (catching in the task) swift · at 1:12 ↗
Task {
    do {
        try lander.fly(to: moon)
    }
    catch {
        lander.abort()
    }
}
Better Swift Concurrency diagnostics (saving the task for later) swift · at 1:21 ↗
let landingTask = Task {
    try lander.fly(to: moon)
}

defer {
    await orbiter.rendezvous(with: lander)
}

try await orbiter.justHangOut(waitingFor: landingTask)
Better 'Sendable' conformances swift · at 1:27 ↗
final class Spacecraft: Sendable {
    ...
    weak let dockedAt: SpaceStation?
    ...
}

class Mission: ~Sendable { ... }

class CrewedMission: Mission, @unchecked Sendable { ... }
More accessible memberwise initializers swift · at 1:48 ↗
struct Briefing {
    internal var topic: String
    internal var scheduledAt: Date
    private  var attendees: [Person] = []
}

// Generated memberwise initializers:
// extension Briefing {
//     private init(topic: String, scheduledAt: Date, attendees: [Person] = []) { 
//          self.topic = topic
//          self.scheduledAt = scheduledAt
//          self.attendees = attendees
//     }
// 
//     internal init(topic: String, scheduledAt: Date) {
//          self.topic = topic
//          self.scheduledAt = scheduledAt
//          self.attendees = []
//     }
// }
'anyAppleOS' availability (before) swift · at 2:03 ↗
extension Mission {
    @available(macOS 27, iOS 27, watchOS 27, tvOS 27, visionOS 27, *)
    func showStatus() { ... }

    @available(macOS 27, iOS 27, watchOS 27, visionOS 27, *)
    @available(tvOS, unavailable)
    func launch() { ... }
  
    #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) || os(visionOS)
    func makeLiveActivityWidget() -> some Widget { ... }
    #endif
}
'anyAppleOS' availability (after) swift · at 2:17 ↗
extension Mission {
    @available(anyAppleOS 27, *)
    func showStatus() { ... }

    @available(anyAppleOS 27, *)
    @available(tvOS, unavailable)
    func launch() { ... }
  
    #if os(anyAppleOS)
    func makeLiveActivityWidget() -> some Widget { ... }
    #endif
}
Controlling warnings with '@diagnose' swift · at 2:40 ↗
@diagnose(DeprecatedDeclaration, as: ignored, reason: "Flying with surplus hardware")
func makeApolloSoyuzMission() -> Mission {
    CrewedMission(
        rocket: makeSaturnIRocket(),
        payload: makeApolloCSM(),
        crew: [.daniellePoole, .nathanMorrison]
    )
}

@diagnose(StrictMemorySafety, as: warning)
func uplinkCommand(from receiver: inout Receiver, to computer: inout Computer) {
    let commandSize = receiver.receiveInt()
    receiver.withReceivedData(byteCount: commandSize) {
        computer.receiveUplinkedCommand($0)
    }
}

@diagnose(ErrorInFutureSwiftVersion, as: error)
func fetchPosition() -> (x: Double, y: Double, z: Double) {
    return self.rotation
}
Clarifying code with module selectors swift · at 3:47 ↗
import Rocket
import GiftShopToys

let rocket1 = SaturnV()            // could mean `Rocket::SaturnV` or `GiftShopToys::SaturnV`
let rocket2 = Rocket.SaturnV()     // prefers `Rocket::Rocket.SaturnV`
let rocket3 = Rocket::SaturnV()    // correctly finds `Rocket::SaturnV`
Clarifying code with module selectors (module selectors work on members, too) swift · at 5:00 ↗
//
// Module Chemistry
//

public protocol Flammable { ... }

extension Flammable {
    /// Set `self` on fire.
    public func fire() { ... }
}

//
// Module HumanResources
//

import Chemistry

public protocol Employee { ... }

extension Employee {
    /// Remove `self` from job.
    public func fire() { ... }
}

public class LaunchPadTechnician: Employee, Flammable { ... }

//
// Module main
//

import HumanResources
import Chemistry

let launchPadTechnician = LaunchPadTechnician(...)

launchPadTechnician.HumanResources::fire()
Task cancellation swift · at 6:26 ↗
// Radio for help

extension Radio {
  func send(_ data: [UInt8] {
    if Task.isCancelled { return }
    // ...
  }
}
  
extension EmergencyTransponder {
  func sendSOS() {
    radio.send(makeSOSPacket())
  }
}
Task cancellation shield swift · at 6:40 ↗
// Radio for help

extension Radio {
  func send(_ data: [UInt8] {
    if Task.isCancelled { return }
    // ...
  }
}
  
extension EmergencyTransponder {
  func sendSOS() {
    withTaskCancellationShield {
    	radio.send(makeSOSPacket())
    }
  }
}
Constructing a new dictionary swift · at 6:53 ↗
// Map values with keys

func makeCalendarDisplayNames(for missions: [Mission: LaunchWindow]) -> [Mission: String] {
    let new: [Mission: String] = .init(
        uniqueKeysWithValues: missions.lazy.map { mission, launchWindow in
            (mission, makeDisplayName(for: mission, in: launchWindow))
        }
    )
    return new
}
Dictionary.mapKeyedValues swift · at 7:06 ↗
// Map values with keys

func makeCalendarDisplayNames(for missions: [Mission: LaunchWindow]) -> [Mission: String] {
    missions.mapKeyedValues { mission, launchWindow in
        makeDisplayName(for: mission, in: launchWindow)
    }
}
The new FilePath type swift · at 7:14 ↗
// FilePath handling macOS-named resources

var path: FilePath = "/var/www/static"
path.components.append("WWDC")
print(path.components)
// [ "var", "www", "static", "WWDC" ]

var path: FilePath = "/var/www/static/..namedresource/rsrc"
print(path.components)
// [ "var", "www", "static" ]
Issue Severity swift · at 7:41 ↗
// Issue severity

@Test(arguments: allRockets)
func testBurn(rocket: Rocket) throws {
    rocket.burn(for: .seconds(150))
    let remaining = rocket.propellantKg / rocket.totalPropellantKg

    if remaining < 0.10 {
        Issue.record(
            "\(rocket.name) remaining fuel is below 10% reserve target",
            severity: .warning
        )
    }

    #expect(remaining > 0.02, "\(rocket.name) propellant critically low - abort")
}
Test Cancellation swift · at 7:52 ↗
// Test Cancellation

@Test(arguments: allRockets)
func testBurn(rocket: Rocket) throws {
    // solid-fuel rocket engines can't be stopped
    if rocket.engineType == .solid {
        try Test.cancel("\(rocket.name) has solid fuel")
    }
 
    rocket.burn(for: .seconds(150))
    let remaining = rocket.propellantKg / rocket.totalPropellantKg

    if remaining < 0.10 {
        Issue.record(
            "\(rocket.name) remaining fuel is below 10% reserve target",
            severity: .warning
        )
    }

    #expect(remaining > 0.02, "\(rocket.name) propellant critically low - abort")
}
XCTest interoperability: Using XCTest from Swift Testing swift · at 8:34 ↗
// XCTest interoperability: Using XCTest from Swift Testing

func checkedTransmitAndReceive(on radio: Radio,
                               packet: Packet,
                               expectedByteCount: Int) throws -> [UInt8] {
    try radio.transmit(bytes: packet.data)
    let bytes = try radio.receive()
    XCTAssertEqual(bytes.count, expectedByteCount)
    return bytes
}

@Test
func pingTest() throws {
    let radio = Radio()
    let bytes = try checkedTransmitAndReceive(on: radio, packet: .ping, expectedByteCount: 8)
    #expect(bytes == [0x00, 0x00, 0xf0, 0x37, 0x0f, 0xc7, 0x00, 0x01])
}
XCTest interoperability: Using Swift Testing from XCTest swift · at 8:48 ↗
// XCTest interoperability: Using Swift Testing from XCTest

class RadioTests: XCTestCase {
    func testPingPacketTransmission() {
        let radio = Radio()
        let bytes = try checkedTransmitAndReceive(on: radio,
                                                  packet: .ping,
                                                  expectedByteCount: 8)

        #expect(bytes == [0x00, 0x00, 0xf0, 0x36, 0x0f, 0xc7, 0x00, 0x02])
    }
}
Subprocess Output Stream swift · at 10:01 ↗
// Subprocess output streaming

let result = try await Subprocess.run(.name("ls"),
                                      input: .none,
                                      output: .sequence,
                                      error: .string(limit:4096)) { execution in
		execution.standardOtput.strings().filter { $0.hasSuffix(".obj") }
}

for try await objectFiles in result.closureOutput {
  	print("Object file: \(objectFile)")
}
Progress Manager - Concurrency swift · at 10:37 ↗
// Progress reporting - Concurrency

let manager = ProgressManager(totalCount: 100)
try await rocket.launch(mission.subprogress(assigningCount: 100))

extension Rocket {
    func launch(_ progress: consuming Subprogress? = nil) async throws {
        let stage = progress?.start(totalCount: 3)
        try await ignite(); stage?.complete(count: 1)
        try await liftoff(); stage?.complete(count: 1)
        try await stageSeparation(); stage?.complete(count: 1)
    }
}
Progress Manager - progress reporting swift · at 10:37 ↗
// Progress reporting - progress reporting

let manager = ProgressManager(totalCount: 100)
try await rocket.launch(mission.subprogress(assigningCount: 100))

Task {
    for await update in Observations({ mission.fractionCompleted }) {
        print("🚀 Mission \(Int(update * 100))%")
    }
}
Progress reporting - metadata swift · at 10:37 ↗
// Progress reporting - metadata

extension Rocket {
    func ascend(_ progress: consuming Subprogress) async throws {
        let stage = progress.start(totalCount: 3)
        stage.detlaV = 3_400; try await burn(); stage.complete(count: 1)
        stage.detlaV = 2_100; try await stageSeparation(); stage.complete(count: 1)
        stage.detlaV = 1_800; try await coast(); stage.complete(count: 1)
    }
}

print("Δv to orbit: \(mission.summary(of: \.deltaV)) m/s")
Directly control inlining (source code) swift · at 20:56 ↗
func histogram<Values>(of values: Values) -> [256 of Int] where Values: Sequence<UInt8> {
    var result = makeInts(randomized: false)
  
    for value in values {
        result[Int(value)] += 1
    }
  
    return result
}

func makeInts(randomized: Bool) -> [256 of Int] {
    if randomized {
        InlineArray { _ in Int.random(in: (.min)...(.max)) }
    } else {
        InlineArray(repeating: 0)
    }
}
Directly control inlining (inlined, but not optimized) swift · at 21:01 ↗
func histogram<Values>(of values: Values) -> [256 of Int] where Values: Sequence<UInt8> {
    var result = if false {                                                  //
                     InlineArray { _ in Int.random(in: (.min)...(.max)) }    //
                 } else {                                                    // Inlined code
                     InlineArray(repeating: 0)                               //
                 }                                                           //

   for value in values {
        result[Int(value)] += 1
    }
    return result
}

func makeInts(randomized: Bool) -> [256 of Int] {
    if randomized {
        InlineArray { _ in Int.random(in: (.min)...(.max)) }
    } else {
        InlineArray(repeating: 0)
    }
}
Directly control inlining (inlined and optimized) swift · at 21:07 ↗
func histogram<Values>(of values: Values) -> [256 of Int] where Values: Sequence<UInt8> {
    var result = InlineArray(repeating: 0)    // Inlined and optimized code

   for value in values {
        result[Int(value)] += 1
    }
    return result
}

func makeInts(randomized: Bool) -> [256 of Int] {
    if randomized {
        InlineArray { _ in Int.random(in: (.min)...(.max)) }
    } else {
        InlineArray(repeating: 0)
    }
}
Directly control inlining (preventing inlining) swift · at 21:30 ↗
@inline(never)
func makeInts(randomized: Bool) -> [256 of Int] {
    if randomized {
        InlineArray { _ in Int.random(in: (.min)...(.max)) }
    } else {
        InlineArray(repeating: 0)
    }
}
Directly control inlining (forcing inlining) swift · at 21:39 ↗
@inline(always)
func makeInts(randomized: Bool) -> [256 of Int] {
    if randomized {
        InlineArray { _ in Int.random(in: (.min)...(.max)) }
    } else {
        InlineArray(repeating: 0)
    }
}
Making generic functions faster with '@specialized'​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ swift · at 21:55 ↗
func histogram<Values>(of values: Values) -> [256 of Int] where Values: Sequence<UInt8> {
    var result = makeInts(randomized: false)
  
    for value in values {
        result[Int(value)] += 1
    }
  
    return result
}

// Note: Specialized function doesn't actually have a directly callable name.
func `histogram of [UInt8]`(of values: [UInt8]) -> [256 of Int] {    //
    var result = makeInts(randomized: false)                         //
                                                                     //
    for value in values {                                            //
        result[Int(value)] += 1                                      // Specialized code
    }                                                                //
                                                                     //
    return result                                                    //
}                                                                    //
Making generic functions faster with '@specialized'​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ (explicitly requesting specialization) swift · at 22:17 ↗
@specialized(where Values == [UInt8])
func histogram<Values>(of values: Values) -> [256 of Int] where Values: Sequence<UInt8> {
    var result = makeInts(randomized: false)
  
    for value in values {
        result[Int(value)] += 1
    }
  
    return result
}

// Note: Specialized function doesn't actually have a directly callable name.
func `histogram of [UInt8]`(of values: [UInt8]) -> [256 of Int] {    //
    var result = makeInts(randomized: false)                         //
                                                                     //
    for value in values {                                            //
        result[Int(value)] += 1                                      // Specialized code
    }                                                                //
                                                                     //
    return result                                                    //
}                                                                    //
Associated types can be '~Copyable' and '~Escapable' swift · at 25:46 ↗
protocol Iterable<Element, Failure>: ~Copyable, ~Escapable {
    associatedtype Element: ~Copyable
    associatedtype IterableIterator: IterableIteratorProtocol<Element, Failure>, ~Copyable, ~Escapable
    associatedtype Failure: Error = Never

    func makeIterableIterator() -> IterableIterator
  
    var underestimatedCount: Int { get }
}

protocol IterableIteratorProtocol<Element, Failure>: ~Copyable, ~Escapable {
    associatedtype Element: ~Copyable
    associatedtype Failure: Error = Never

    mutating func nextSpan(maximumCount: Int) throws(Failure) -> Span<Element>
  
    mutating func skip(by maximumOffset: Int) throws(Failure) -> Int
}
The problem with existing accessors swift · at 27:28 ↗
@safe public struct UniqueBox<Value>: ~Copyable {
    private let valuePointer: UnsafeMutablePointer<Value>

    public init(_ value: consuming Value) {
        valuePointer = UnsafeMutablePointer.allocate(capacity: 1)
        valuePointer.initialize(to: value)
    }

    public var value: Value {
        get { valuePointer.pointee }
        set { valuePointer.pointee = newValue }
    }

    deinit {
        valuePointer.deinitialize(count: 1)
        valuePointer.deallocate()
    }
}
'borrow' and 'mutate' accessors swift · at 28:19 ↗
@safe public struct UniqueBox<Value: ~Copyable>: ~Copyable {
    private let valuePointer: UnsafeMutablePointer<Value>

    public init(_ value: consuming Value) {
        valuePointer = UnsafeMutablePointer.allocate(capacity: 1)
        valuePointer.initialize(to: value)
    }

    public var value: Value {
        borrow { valuePointer.pointee }
        mutate { &valuePointer.pointee }
    }

    deinit {
        valuePointer.deinitialize(count: 1)
        valuePointer.deallocate()
    }
}
Using 'MutableRef' to eliminate repeated accesses (with un-hoisted access) swift · at 30:14 ↗
func updateCount<Key: Hashable>(
    for key: Key,
    from sets: [Set<Key>],
    in counts: inout [Key: Int]
) {
    for set in sets {
        if set.contains(key) {
            counts[key, default: 0] += 1
        }
    }
}
Using 'MutableRef' to eliminate repeated accesses (hoisted by 'inout' parameter) swift · at 30:34 ↗
func updateCount<Key: Hashable>(
    for key: Key,
    from sets: [Set<Key>],
    in counts: inout [Key: Int]
) {
    func updateCountImpl(count: inout Int) {
        for set in sets {
            if set.contains(key) {
                count += 1
            }
        }
    }
    
    updateCountImpl(count: &counts[key, default: 0])
}
Using 'MutableRef' to eliminate repeated accesses (hoisted by 'MutableRef') swift · at 30:41 ↗
func updateCount<Key: Hashable>(
    for key: Key,
    from sets: [Set<Key>],
    in counts: inout [Key: Int]
) {
    var countRef = MutableRef(&counts[key, default: 0])

    for set in sets {
        if set.contains(key) {
            countRef.value += 1
        }
    }
}

Resources