Jupyo's Daily Story
Announcing Swift 6 본문
Swift 6가 공식 출시되어 더 많은 플랫폼과 도메인으로 확장됩니다. 앱 개발 외에도 Swift는 라이브러리, 인터넷 서비스, 성능이 중요한 코드에 적합하며, 이번 릴리즈에는 저수준 프로그래밍, 임베디드 Swift, Linux 와 Window 지원, 크로스 플랫폼 API 및 Swift Testing 라이브러리가 추가되었습니다.
언어와 표준 라이브러리
동시성
Swift 6는 새로운 언어 모드로 동시성 코드에서 데이터 경합을 컴파일러 오류로 감지해 안전성을 강화했습니다. Swift 5.10에서는 -strict-concurrency=complete 플래그로 경고를 받을 수 있었으나, Swift 6에서는 Sendable 추론과 새로운 분석 도입으로 경고의 정확도가 높아졌으며, 저수준 동시성 API를 위한 새로운 동기화 라이브러리도 포함되어 있습니다.
Typed throws
Swift 6는 함수 시그니처에서 던지는 오류의 타입을 명시할 수 있도록 하여, 제네릭 코드 및 메모리 제한 환경에서 유용하게 사용될 수 있습니다.
func parseRecord(from string: String) throws(ParseError) -> Record {
// ...
}
parseRecord(from:) 호출은 Record 인스턴스를 반환하거나 ParseError 타입의 오류를 던집니다. do...catch 블록 내에서 catch 절의 오류 변수는 자동으로 ParseError 타입으로 추론됩니다.
do {
let record = try parseRecord(from: myString)
} catch {
// 'error' has type 'ParseError'
}
- 타입이 지정된 throws는 throwing과 non-throwing 함수를 일반화합니다.
- throws(오류 유형 없음)은 throws(any Error)로 지정된 함수와 동일합니다.
- non-throwing 함수는 throws(Never)로 지정된 함수와 동일하며, 호출 시 오류 처리가 필요 없습니다.
타입이 지정된 throws는 제네릭 함수에서도 매개변수로부터 오류 유형을 전파하는 데 사용될 수 있으며, 이는 rethrows보다 더 정확한 방식입니다.
extension Sequence {
func map<T, E>(_ body: (Element) throws(E) -> T) throws(E) -> [T] {
// ...
}
}
- throws(ParseError) 클로저가 주어지면, map은 ParseError를 던집니다.
- non-throwing 클로저가 주어지면, E는 Never로 추론되어 map은 던지지 않습니다.
OwnerShip
Swift 5.9는 고유한 소유권을 모델링하기 위해 ~Copyable 구문을 사용하여 non-copyable 타입을 도입하였습니다. Swift 6는 이제 이러한 타입을 제네릭 시스템과 함께 지원하여 copyable과 non-copyable 타입 모두에서 작동하는 제네릭 코드를 작성할 수 있게 합니다.
protocol Drinkable: ~Copyable {
consuming func use()
}
struct Coffee: Drinkable, ~Copyable { /* ... */ }
struct Water: Drinkable { /* ... */ }
func drink(item: consuming some Drinkable & ~Copyable) {
item.use()
}
drink(item: Coffee())
drink(item: Water())
- Drinkable 프로토콜은 준수 타입에 Copyable 요구사항이 없으므로, non-copyable인 Coffee와 copyable인 Water 모두 제네릭 drink 함수에 전달 가능합니다.
- Switch 문은 이제 enum 패턴 매칭 작업 내에서 복사를 피할 수 있습니다. 특히 Array와 Dictionary와 같은 copy-on-write 컨테이너 기반의 copyable payloads에 대해 성능 이점을 제공합니다.
- non-copyable 타입은 표준 라이브러리에서 사용되고 있습니다.
- Atomic 타입: ~Copyable 기반
- Optional, Result: non-copyable 타입 래핑 가능
- Unsafe buffter pointer: non-copyable 요소를 가리킴
- C++ 상호 운용성: non-copyable 타입을 사용하여 C++의 이동 전용 타입을 Swift에 노출
C++ interoperability (상호 운용성)
Swift 6에서는 C++ 이동 전용 타입, 가상 메서드, 기본 인수 및 std::map과 std::optional과 같은 더 많은 표준 라이브러리 타입에 대한 상호 운용성 지원을 확장합니다.
복사 생성자가 없는 C++ 타입은 이제 Swift 6에서 ~Copyable로 non-copyable 타입으로 접근할 수 있습니다. 더 나은 성능을 위해 복사 생성자를 가진 C++ 타입을 ~Copyable로 노출할 필요가 있을 때는 새로운 SWIFT_NONCOPYABLE 주석을 C++ 타입에 적용할 수 있습니다.
Swift는 이제 SWIFT_SHARED_REFERENCE 또는 SWIFT_IMMORTAL_REFERENCE로 주석이 달린 타입에서 C++ 가상 메서드를 호출하는 것을 지원합니다.
기본 인수 값을 가진 C++ 함수나 메서드를 호출할 때, Swift는 이제 이러한 기본 값을 존중하며, 인수를 명시적으로 전달할 필요가 없습니다.
Embedded Swift
Embedded Swift는 제네릭 특수화를 활용하여 작고 독립적인 바이너리를 생성합니다. 런타임이나 타입 메타데이터에 의존하지 않기 때문에, Embedded Swift는 메모리 제약이 심한 플랫폼과 제한된 런타임 종속성을 가진 저수준 환경에서 사용하기에 적합합니다.
128-bit Integers
Swift 6은 signed 128비트 정수 타입과 unsigned 128비트 정수 타입을 추가하여 low-level 정수 기본 타입의 집합을 완성합니다.
디버깅 (Debugging)
Custom LLDB summaries with @DebugDescription
Swift 6에서는 @DebugDescription이라는 새로운 매크로를 도입하여, 디버깅 시 LLDB에서 객체가 어떻게 표시되는지를 간편하게 커스터마이징할 수 있습니다. 이 매크로를 사용하면 p 명령어나 Xcode, VSCode의 변수 보기 창에서 객체를 특정 방식으로 포맷할 수 있으며, 이 과정에서 임의의 코드를 실행하지 않고도 포맷팅 규칙을 적용할 수 있습니다.
기존에 Swift에서 CustomDebugStringStringConverible을 준수하는 타입은 debugDescription 속성을 통해 객체의 설명을 문자열로 반환하고, po 명령어를 통해 이 속성이 호출되었습니다. 그러나 p 명령어는 이와 달리 객체의 저장된 속성 값을 사용하여 LLDB 타입 요약 포맷터를 통해 직접 포맷팅을 했습니다.
@DebugDescription 매크로는 LLDB의 p 명령어에서도 이 사용자 정의 포맷팅을 적용할 수 있게 해줍니다. 이 매크로는 debugDescription 속성에서 간단한 문자열 보간을 LLDB 요약으로 변환하며, p 명령뿐 아니라 Xcode와 VSCode의 변수 보기 창에서도 적용됩니다. 만약 기존 CustomDebugStringConvertible 구현이 @DebugDescription의 요구 사항에 맞지 않거나, 더 정교한 LLDB 요약을 원한다면, 별도의 LLDB 설명 문자열을 정의할 수도 있습니다.
@DebugDescription
struct Organization: CustomDebugStringConvertible {
var id: String
var name: String
var manager: Person
// ... and more
var debugDescription: String {
"#\(id) \(name) [\(manager.name)]"
}
}
(lldb) p myOrg
(Organization) myOrg = "'#100 Worldwide Travel [Jonathan Swift]'"
명시적 모듈을 사용한 시작 성능 개선
Swift 6에서는 명시적 모듈 빌드를 사용한다면 디버거에서 시작 성능이 크게 개선됩니다. 로컬에서 빌드한 코드를 디버깅할 때, LLDB는 이제 프로젝트 빌드 아티팩트에서 명시적으로 빌드된 Swift와 Clang 모듈을 직접 가져올 수 있습니다. 이를 통해 소스에서 암묵적 Clang 모듈 의존성을 다시 컴파일할 필요가 없으며, 이는 시간이 오래 걸릴 수 있고 헤더 검색 경로에 민감한 문제를 피할 수 있습니다.
Libraries
Foundation
Swift 6는 모든 플랫폼에서 Foundation의 구현을 통합했습니다. 현대적이고 이식 가능한 Swift 구현은 플랫폼간 일관성을 제공하며, 더 견고하고 오픈 소스입니다. macOS와 iOS는 Swift 5.9부터 Swift로 구현된 Foundation을 사용하기 시작했으며, Swift 6에서는 이 개선 사항을 Linux와 Windows로 확장합니다.
- 주요 변경 사항
- JSONDecoder, URL, Calendar, FileManager, ProcessInfo와 같은 핵심 타입들이 Swift로 완전히 재구현되었습니다. 이제 macOS 15와 iOS 18에서 사용되는 동일한 구현이 모든 플랫폼에서 사용되며, 크로스 플랫폼 일관성, 신뢰성, 성능을 새로운 수준으로 끌어올립니다.
- 최근에 발표된 FormatStyle, ParseStrategy, Predicate, JSON5 등의 API가 이제 모든 Swift 플랫폼에서 사용 가능합니다.
- Expression, 달력 열거 개선, 달력 반복 규칙, 포맷 스타일 향상 등의 새로운 Foundation API가 macOS, iOS, Linux, Windows에서 동시에 제공되며, 이는 커뮤니티의 참여로 개발되었습니다.
- 추가 사항
- 만약 현재 Linux나 Windows 앱에서 Swift 툴체인의 Foundation 라이브러리를 사용 중이라면, 이 모든 개선 사항을 자동으로 받을 수 있습니다.
- 앱의 바이너리 크기가 민감한 경우, 국제화 및 현지화 데이터를 생략한 FoundationEssentials 라이브러리를 가져와 더 간소화된 기능만 사용할 수 있습니다.
Swift Testing
Swift 6는 Swift Testing이라는 새로운 테스트 라이브러리를 도입했습니다. 이 라이브러리는 Swift에 맞춰 처음부터 설계된 것으로, 테스트 작성과 관리가 쉽도록 표현력 있는 API를 제공합니다. 또한 테스트 실패 시 #expect와 같은 매크로를 사용해 상세한 출력을 제공하며, 매개변수화(parameterization) 같은 기능을 통해 테스트를 다양한 인수로 반복 실행할 수 있어 대규모 코드베이스에도 잘 확장됩니다.
@Test("Continents mentioned in videos", arguments: [
"A Beach",
"By the Lake",
"Camping in the Woods"
])
func mentionedContinents(videoName: String) async throws {
let videoLibrary = try await VideoLibrary()
let video = try #require(await videoLibrary.video(named: videoName))
#expect(video.mentionedContinents.count <= 3)
}
Swift Testing은 매크로의 이점을 최대한 활용합니다. @Test와 @Suite와 같은 첨부 매크로를 사용해 각각 테스트 함수와 테스트 스위트를 선언하며, 특징(traits)이라는 인수를 받아 다양한 동작을 커스터마이징할 수 있습니다. #expect와 #require 같은 표현 매크로는 예상되는 동작을 검증하고, 표현식과 하위 값들을 풍부하게 표현하여 자세한 실패 메시지를 제공합니다.
- Swift Testing은 Swift 6 툴체인에 직접 포함되어 있어 별도의 패키지 의존성을 선언할 필요가 없습니다.
- 테스트 시 Swift Testing이나 그 의존성을 빌드할 필요가 없으며, 매크로 구현이 미리 빌드된 상태로 제공됩니다.
- Swift 패키지 관리자는 Swift Testing 테스트와 기존 XCTests를 모두 빌드 및 실행하며, 두 라이브러리의 결과를 로그 출력에 표시합니다.
- Swift Testing은 모든 Apple 플랫폼, Linux, Windows를 포함해 Swift가 공식적으로 지원하는 모든 플랫폼에서 사용할 수 있습니다.
'Swift' 카테고리의 다른 글
GCD (Grand Central Dispatch) (1) | 2024.09.25 |
---|---|
튜플 (Tuples) (0) | 2024.09.25 |
옵셔널 (Optional) (2) | 2024.09.22 |
열거형 (Enumeration) (0) | 2024.09.19 |
변수(Variable)와 상수(Constant) (0) | 2024.09.18 |