-
Swift의 새로운 기능
Swift 관련 업데이트를 확인해 보세요. 일상적인 인체공학, 향상된 동시성, 더 안전한 고성능 코드를 위한 업데이트 등 언어 관련 최신 혁신 기술을 알아보세요. Embedded Swift의 워크플로와 언어 상호 운용성 개선 사항 및 업데이트를 살펴보세요.
챕터
- 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
리소스
관련 비디오
WWDC26
-
비디오 검색…
-
-
1:12 - Better Swift Concurrency diagnostics (catching in the task)
Task { do { try lander.fly(to: moon) } catch { lander.abort() } } -
1:21 - Better Swift Concurrency diagnostics (saving the task for later)
let landingTask = Task { try lander.fly(to: moon) } defer { await orbiter.rendezvous(with: lander) } try await orbiter.justHangOut(waitingFor: landingTask) -
1:27 - Better 'Sendable' conformances
final class Spacecraft: Sendable { ... weak let dockedAt: SpaceStation? ... } class Mission: ~Sendable { ... } class CrewedMission: Mission, @unchecked Sendable { ... } -
1:48 - More accessible memberwise initializers
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 = [] // } // } -
2:03 - 'anyAppleOS' availability (before)
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 } -
2:17 - 'anyAppleOS' availability (after)
extension Mission { @available(anyAppleOS 27, *) func showStatus() { ... } @available(anyAppleOS 27, *) @available(tvOS, unavailable) func launch() { ... } #if os(anyAppleOS) func makeLiveActivityWidget() -> some Widget { ... } #endif } -
2:40 - Controlling warnings with '@diagnose'
@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 } -
3:47 - Clarifying code with module selectors
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` -
5:00 - Clarifying code with module selectors (module selectors work on members, too)
// // 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() -
6:26 - Task cancellation
// Radio for help extension Radio { func send(_ data: [UInt8] { if Task.isCancelled { return } // ... } } extension EmergencyTransponder { func sendSOS() { radio.send(makeSOSPacket()) } } -
6:40 - Task cancellation shield
// Radio for help extension Radio { func send(_ data: [UInt8] { if Task.isCancelled { return } // ... } } extension EmergencyTransponder { func sendSOS() { withTaskCancellationShield { radio.send(makeSOSPacket()) } } } -
6:53 - Constructing a new dictionary
// 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 } -
7:06 - Dictionary.mapKeyedValues
// Map values with keys func makeCalendarDisplayNames(for missions: [Mission: LaunchWindow]) -> [Mission: String] { missions.mapKeyedValues { mission, launchWindow in makeDisplayName(for: mission, in: launchWindow) } } -
7:14 - The new FilePath type
// 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" ] -
7:41 - Issue Severity
// 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") } -
7:52 - Test Cancellation
// 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") } -
8:34 - XCTest interoperability: Using XCTest from Swift Testing
// 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]) } -
8:48 - XCTest interoperability: Using Swift Testing from XCTest
// 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]) } } -
10:01 - Subprocess Output Stream
// 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)") } -
10:37 - Progress Manager - Concurrency
// 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) } } -
10:37 - Progress Manager - progress reporting
// 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))%") } } -
10:37 - Progress reporting - metadata
// 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") -
20:56 - Directly control inlining (source code)
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) } } -
21:01 - Directly control inlining (inlined, but not optimized)
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) } } -
21:07 - Directly control inlining (inlined and optimized)
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) } } -
21:30 - Directly control inlining (preventing inlining)
@inline(never) func makeInts(randomized: Bool) -> [256 of Int] { if randomized { InlineArray { _ in Int.random(in: (.min)...(.max)) } } else { InlineArray(repeating: 0) } } -
21:39 - Directly control inlining (forcing inlining)
@inline(always) func makeInts(randomized: Bool) -> [256 of Int] { if randomized { InlineArray { _ in Int.random(in: (.min)...(.max)) } } else { InlineArray(repeating: 0) } } -
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 // } // -
@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 // } // -
25:46 - Associated types can be '~Copyable' and '~Escapable'
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 } -
27:28 - The problem with existing accessors
@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() } } -
28:19 - 'borrow' and 'mutate' accessors
@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() } } -
30:14 - Using 'MutableRef' to eliminate repeated accesses (with un-hoisted access)
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 } } } -
30:34 - Using 'MutableRef' to eliminate repeated accesses (hoisted by 'inout' parameter)
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]) } -
30:41 - Using 'MutableRef' to eliminate repeated accesses (hoisted by 'MutableRef')
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 } } }
-
-
- 0:07 - Introduction
A preview of the session's four topics: language improvements, library updates, cross-platform support, and performance tuning in Swift 6.3 and 6.4.
- 0:44 - Everyday Language Improvements
Quality-of-life changes land in Swift 6.4, including optional parentheses removal, concurrency task warnings, weak let, ~Sendable, and a new memberwise initializer.
- 1:55 - anyAppleOS Availability
Swift now lets you condense multi-platform availability attributes into a single anyAppleOS condition, reducing boilerplate across iOS, macOS, watchOS, and more.
- 3:02 - @diagnose Attribute
The new @diagnose attribute gives fine-grained control over warnings within a specific declaration, letting you suppress, enable, or promote them to errors.
- 3:52 - Module Selectors (::)
Swift 6.3 introduces double-colon module selector syntax to unambiguously reference a type or member from a specific module when name conflicts arise.
- 5:59 - Library Updates
Updates across four key libraries: the standard library, Swift Testing, Subprocess, and Foundation.
- 6:16 - Standard Library
New additions include a task cancellation shield, mapKeyedValues for dictionaries, and a cross-platform FilePath type.
- 7:31 - Swift Testing Updates
Swift Testing gains configurable issue severity, dynamic test cancellation, flaky test repetition, and improved two-way interoperability with XCTest.
- 9:29 - Subprocess 1.0
Subprocess reaches 1.0 with a refined API, improved error handling, convenient line-by-line output streaming, and expanded cross-platform support.
- 10:14 - Foundation
Foundation gains a new ProgressManager type and continues its Swift migration, with performance improvements to Data, NSURL, and CFURL.
- 11:59 - Beyond Apple Platforms
Swift 6.4 extends language interoperability and broadens its reach to new environments including web, Android, and embedded devices.
- 12:35 - Swift–C Interoperability (@C attribute)
The new @C attribute lets you expose Swift functions directly to C, enabling safe, incremental migration of C codebases to Swift.
- 15:09 - Swift-Java
The Swift-Java package now supports async and throwing Swift functions from Java, constrained extensions, and conforming Java classes to Swift protocols.
- 16:03 - Editor support
The Swift VSCode extension adds Swiftly integration for toolchain management and is now available on the OpenVSX marketplace for editors like Cursor and VSCodium.
- 16:44 - WebAssembly (Wasm) & JavascriptKit
Swift can now compile to WebAssembly, with JavascriptKit improvements delivering up to 40x faster safe bridging between Swift and JavaScript.
- 18:08 - Embedded Swift
Embedded Swift expands its language subset with existential types, untyped throws, and improved DWARF debug info for coredump debugging on constrained hardware.
- 19:59 - Performance Tuning
Two areas of advanced performance work: explicit optimizer control and extensions to the ownership system to prevent unnecessary copying.
- 21:29 - Optimizer Control: @inline(always) & @specialized
New @inline(always) and @specialized attributes give you direct control over the compiler's inlining and generic specialization decisions.
- 24:29 - Ownership System & Noncopyable Types
Equatable, Comparable, Hashable, and associated types now work with noncopyable and non-escapable types, broadening the ownership system's reach.
- 26:18 - Iterable Protocol & Borrow/Mutate Accessors
A new Iterable protocol enables efficient borrow-based for loops over noncopyable elements, while new borrow and mutate accessors eliminate costly copies in computed properties.
- 28:57 - New Standard Library Types: UniqueBox, UniqueArray, Ref
The standard library gains UniqueBox, UniqueArray, Continuation, and the new Ref/MutableRef types for safe, high-performance ownership patterns.
- 31:11 - The Future of Swift
Highlights open-source progress including Swift Build, new workgroups for build, networking, Windows, and Android, and an invitation to participate at forums.swift.org.