apple/WWDC

Swift의 새로운 기능 (What's new in Swift) - WWDC25

lgvv 2025. 7. 21. 00:16

Swift의 새로운 기능 (What's new in Swift) - WWDC25

Swift 6.2의 새로운 기능과 개선점 소개
 

 
swiftly는 버전 관리자로 원래 Linux상 Swift Toolchain 관리를 간소화하기 위해 오픈소스 커뮤니티에서 개발
올해부터 swiftly는 macOS를 지원하고 swift.org에서 1.0 릴리즈를 만나볼 수 있음.
 
`> swiftly install 6.1.3`으로 설치하거나 `>swiftly install main-snapshot`을 통해 깃헙 main 브랜치에서 설치하여 개발중인 기능을 설치할 수 있음.
 

 
Xcdoe에서 swiftly가 설치한 Toolchain은 메뉴에서 사용할 수 있음.
VSCode에서는 Toolchain을 선택할 수 있음.
 

 
VSCode에서는 올해부터 swift.org의 공식 인증을 받아 배포됨.
올해에는 Backgound Indexing과 Swift Package Manager를 더 잘 볼 수 있으며, 문서 확인하는 방법도 개선됨.
 
자세한 내용은 오픈소스로 개발되어서 블로그 확인할 것.
 

 
Swift 6.2는 매크로 기반 API를 사용하는 프로젝트의 클린 빌드 시간을 크게 개선.
특정 패키지의 매크로를 사용하는 프로젝트가 있다고 가정.
이전에는 Swift PM이 먼저 매크로를 지원하는 라이브러리인 Swift Snytax의 소스를 가져와야 했음.
 
Fetch swift-syntax > Build swift-syntax > Build Stringify > BUild project로 코드를 구축
Build된 swift-syntax는 캐시가 가능했지만 클린 빌드에 필요한 시간이 더 많이 필요했음.
이는 특히 지속적으로 환경이 통합되는 과정에서 눈에 띄는 차이로 나타남.
 

 
Build 속도를 높이기 위해 Swift PM 및 Xcode의 최신 릴리즈는 prebuild swift-syntax 의존성을 지원함.
이는 무거운 Build 단계를 완전히 없애고 일부 프로젝트의 경우 빌드 시 몇분이상 줄어듦
 

 
매크로를 제공하는 패키지를 직접 보유하고 있다면 패키지가 Swift Syntax의 태그된 릴리즈에 의존하는 한 최적화의 이점을 누릴 수 있음.
 
 

Diagnositcs


하지만 생산성은 빌드 성능에 의해서만 좌우되지 않음.
때로는 컴파일러가 발견한 문제를 해결하느라 늦어질 수 있음.
 
Swift 6에서 동시성 오류를 발견해 컴파일러가 오류를 내줌. 중요한 오류이긴 하지만 해결법은 모호할 수 있음.
Swift 6.2에서는 이러한 다양한 컴파일러 오류 진단 카테고리를 늘림.
 

 
일반적인 경고와 오류에 대한 설명을 제공하기 때문에 문제를 이해하고 견고한 해결법을 찾을 수 있도록 도와줌.
문서는 IDE와 swift.org에서 온라인으로 접근 가능.
 

 
진단의 작동 방식을 제어하는 것도 중요할 수 있음.
코드에서 경고를 없애기 위해 "wanings as errors"로 IDE에서 설정할 수 있음.
 

 
이는 해결하기 쉬운 간단한 경고들에는 좋지만 더이상 사용되지 않는 API와 같은 경고에는 즉시 적용하지 않는 것이 좋을 수 있음.
 

 
Swift Pacakage는 오류를 설정할 수 있는 유연성을 제공함.
예를 들어서 모든 경고를 오류로 처리하는 것을 기본값으로 두고 DeperecatedDeclation은 warning으로 둘 수 있음. 
 
반대로 일부 카테고리만 error로 두고자 한다면 특정 경고만 error로 변경할 수 있음.
컴파일러 경고에 대한 제어 기능을 추가한 것을 커뮤니티의 주도로 Swift를 개선해 작업자가 개선을 이룸
 

 
Swift 6.2에서는 디버깅 코드의 경험이 크게 개선되었음.
Swift Task를 살펴보면 LLDB가 스레드 간의 전환이 필요한 경우에도 비동기 함수의 실행을 따라가는 것을 볼 수 있음.
 
쉽게 추적할 수 있도록 Task의 이름을 지정할 수도 있음. 
지정된 이름은 Instuments의 프로파일링에도 나타남.
 
swift task info와 같은 새로운 커맨드를 사용해 우선순위와 children에 대한 정보도 확인할 수 있음.
올해에는 명시적으로 빌드된 모듈 덕분에 디버깅 반응성이 더 개선됨. 
명시적 모듈 의존성은 빌드 시 병렬 처리 및 재사용 가능하게 하는 빌드 시스템임.
 

 
명시적으로 빌드된 모듈 이전에 Xcode 빌드 및 디버거는 완전히 분리된 모듈 그래프를 사용
이제 디버거는 빌드의 모듈을 완전히 재사용할 수 있음.
 
명시적으로 빌드된 모듈은 Xcode 26에서 기본적으로 활성화 됨.
 
 

 
Swift 6.2는 Foundation API의 인터페이스를 현대화하고 간소화하는 새로운 API를 제공
Swift 코드 작성 경험을 개선하기 위해 Foundation 작업 Group은 Subprocess를 도입
 
Subprocess 이름이 포함된 문자열을 제공하면 실행 메서드가 $PATH 환경 변수에 기반하여 실행 파일을 조회함.
대부분의 경우 파일 경로를 통해 Subprocess를 실행하여 실행 파일까지의 전체 경로를 식별함.
 
하위 프로세스가 종료되면 종료 상태, 표준 출력 및 프로세스 실행에 대한 다른 정보를 검토할 수 있음.
 

 
notificationCenter 사용할 때는 알림에 대한 forName을 잘못 작성하거나 userInfo는 타입이 지정되지 않은 딕셔너리에 저장되며 여기에는 올바른 키를 사용해 value에 접근해 올바른 타입에 맞게 동적으로 변환해야 함.
 
또한 queue에 .main을 지정하여 메인 스레드에서 동작하는걸 보장했음에도 MainActor의 API에 접근할 때 동시성 오류가 나타날 수 있음

notification과 페이로드는 이제 구체적인 타입을 지원하며, 컴파일러 단계에서 지원해줌
 

 
알림에 대한 등록에서는 MainActorMessage는 Main 스레드에서 동기적으로 동작하도록 보장하며
AsyncMessage는 임의의 스레드에서 비동기적으로 동작함.
 

 
addObserver에 대한 관찰은 보다 일반적인 옵저버 패턴을 기반으로 함.
Observation 라이브러리는 객체 그래프의 상태 변화를 자동으로 추적하는 범용 API를 제공 
 
@Observable 매크로를 통해 Swift 6.2는 관찰 가능한 타입의 AsyncSequence로 상태 스티리밍 하는 방법을 도입함.
클로저가 있는 새로운 Observations 인스턴스를 생성하는 것을 시작으로 클로저에서는 변경 사항을 관찰하려는 값을 연산할 수 있음.
 
플레이어에 선언된 관찰 가능한 값을 기반으로 업데이트 된 값을 얻을 수 있음.
업데이트는 trasaction에 따라서 발생함. 
 

 
Observation은 Transaction 단위로 수행되는데, willSet이 호출될 때 시작되며, Task.yield시 종료됨
업데이트 된 값에는 두 변경 사이의 모든 변경사항이 포함되어서 여러 속성에 대한 업데이트가 발생해도 일관성 없는 객체에 관찰 업데이트가 전달되지 않음.
 


여러 속성에 대한 동기적으로 업데이트가 발생해도 일관성 없는 객체에 관찰에 대해서 업데이트가 전달되지 않음.
score와 item을 모두 동기적으로 업데이트하면 두 변경 사항을 모두 업데이트 한 값 한개만 얻게 됨.
이는 AsyncSequence을 준수하므로 for-await loop를 사용해 업데이트 된 값을 관찰할 수 있음.
 

 
CI와 같은 원격환경에서만 실패하는 경우가 있는데 이와 같은 경우는 때로 실패를 확인하기 어려운 경우가 존재함.
실패를 확인하려면 실패와 관련한 컨텍스트가 더 필요함.
 

 
Swift 6.2 부터는 테스트 실패 진단에 필요한 커스텀 파일을 준비함.
Swift 6.2는 또한 종료 테스트를 지원해 특정 조건하에 종료하려는 코드를 테스트할 수 있도록 해줌.
 
예를들어 precondition을 통해 가정을 검증하는 함수를 작성할 때 전제 조건이 충족되지 않으면 성공하는 테스트 케이스를 작성할 수 있음.
#expect 또는 #required에 processExitsWith 인자를 전달해 종료 테스트를 작성함.
 

 
Embeded Swift는 매우 제약적인 환경에서 코드를 작성할 수 있게 해주는 Swift의 subset임.
값 및 참조 유형, 클로저, 오류처리, 제네릭 등 핵심 Swift의 지원하는 컴파일 모드 등 Apple에서는 iPhone에서 실행되는 가장 낮은 수준의 소프트웨어에서 Embeded Swift를 사용함.
 
iOS 26에서는 Embeded Swift는 CPU와 GPU 사이의 공유 메모리 페이지에 대한 접근을 관리하는 보조 프로세서에서 사용됨.
 

 
문자열 전체를 다루며, 프로토콜을 준수하는 클래스를 사용할 수 있음
또한 InlineArray와 Span을 사용할 수 있음.
 
 

 
메모리 안전 코드는 보안에도 좋고 Apple Platform에 맞춘 코드로 만들기 위해 노력해옴.
C로 작성된 코드를 포함할 때는 포인터를 수용하는 API를 사용하는 것이 일반적인 것에 반해 보안이 중요한 코드는 중요한 상황에서 안전하지 않은 코드는 최대한 피해야 하며, 이를 피할 수 없다면 최소한 식별하기 쉽게라도 만들어야 함. 
 


Swift 6.2에서는 안전하지 않은 모드를 알리는 워닝이 추가되었고, 해당 코드는 모드에 필요한 주석은 보안을 위해 어떤 코드 부분이 추가로 필요한지 식별하는데 도움이 됨.
 

 
이와 동시에 Swift 6.2에서는 Span과 같이 안전한 유형을 통해 Swift에 API를 불러오는 C 및 C++ 헤더에 대한 새로운 주석도 지원함.

C, C++, Swift를 상호 윤용하는 `Safely mix C, C++ and Swift` 비디오를 참고할 것.
 

 
Swift는 WebKit과 Messages에 도입하며 두 요소 모두 신뢰할 수 없는 입력을 처리하기 때문에 안전하지 않은 API를 처리하는것이 중요함.
 

 
Swift Server 생태계에서 Swift가 사용되는 역할을 보고자 함.
Java로 작성된 코드를 Swift로 재작성하면서 언어의 효율적인 네이티브 코드와 결정론적 메모리 관리 덕분에 서비스 처리량이 40프로 감소하고 하드웨어 요구사항이 50프로 감소함.
 
Thing Cloud는 Swift를 통해 서버 비용을 3배 절감하고 평균 응답 시간을 400% 개선할 수 있음.
올해는 gRPC 2.0을 릴리즈했고, 많은 라이브러리를 보유하고 있고 확장하고 있음.
 

 
기존 서버는 Java로 대부분 작성되어 있었고, swift-java를 통해 두 언어가 원활하게 상호 운용되도록 하는 것을 목표로 함.
 

 
Swift - Java 상호운용은 두 코드가 서로 호출할 수 있도록 바인딩을 생성할 수 있음.
이러한 바인딩은 과도한 오버헤드 없이도 각 언어에서 얻은 값의 네이티브 표현을 래핑하도록 설계.
Swift - Java 프로젝트는 현재 실험중이며 빠르게 진화하고 있음.

 
Apple은 로컬 테스트 환경을 위해 Mac에서 실행하는 Linux 컨테이너 기반 도구 구축시 새로운 라이브러리인 컨테이너 라이브러리를 릴리즈 함.
이는 완전히 Swift로 구현되었고 보안, 개인정보 보호 및 성능에 중점을 둠.
시스템 수준에서 Swift를 활용한 예제임.
 

 
Swift 6.2에서는 서버와 임베디드에서 인기있는 운영체제인 FreeBSD를 Swift가 지원하는 플랫폼으로 추가함.
또한 Swift는 WebAssembly의 도움을 받고 있는데 이동성, 보안 및 고성능에 영향을 맞춰 가상 서버 어플리케이션을 구축한 후에 배포할 수 있음
 

 
JavaScriptKit은 SwiftWasm 조직이 개발한 오픈소스 패키지로 Swift API와 JavaScript 런타임과 상호작용 할 수 있음.
최종 바이너리를 컴팩트하게 만들기 위해 Embeded Swift로 앱을 컴파일링하지만 대부분의 코드는 Swift 코드임.
SwiftBuild를 호출해 WASM앱을 컴파일하도록 구성되었음.
 

 
배열을 사용할 때는 동적 크기 조정을 지원하기 위해서 배열은 힙 할당 버퍼에 대한 참조를 저장함.
더 많은 요소가 추가되고 배열이 용량이 도달하면 동적으로 새 메모리를 할당하고 기존 Elements를 복사해야 함.
 
성능에 중요한 코드 프로파일링 시 제거해야 하는 배열 버퍼에 대한 메모리 할당 또는 참조 계산을 보게될 수 있음.
배열의 크기가 변하지 않으면 힙 할당 비용을 지불할 필요가 없음.
 

 
InlineArray는 Element를 위한 인라인 스토리지가 있는 새로운 고정 크기 배열 타입.
InlineArray는 Element를 Heap에 저장하는 대신 스택에 바로 저장함. 
 
Elements가 스택에 저장되거나 추가 힙 할당 없이 다른 타입 내에 직접 저장될 수 있음을 의미 
InlineArray는 copyable 혹은 noncopyable 타입을 저장함. 
 

 
copyable를 저장할 때는 InlineArray를 복사할 수 있으며 스택에 복사됨.
 

 
정수를 매개 변수로 허용하는 새로운 제네릭 기능을 사용하여 타입을 일부로 크기를 작성함.
일반 배열과 바찬가지로 InlineArray의 타입은 배열에서 추론할 수도 있음.
 
컴파일 시점의 InlineArray 크기를 알면 인덱스가 크기보다 작을 때 경계를 확인하지 않아도 되는 등 더 많은 최적화 가능함.

 
container type은 기본적으로 underlying storage에 직접 접근해야할 때가 많음.
원래 컨테이너의 레이아웃을 알 필요 없이 연속되는 메모리에서 로컬 처리를 수행하는데 유용함. 
 
예를 들어서 함수가 인전한 스토리지에서 Swift 6.2 이전에는 일반적으로 UnsafeBufferPointer를 사용해야 함.
 

 
Span이라는 새로운 타입을 통해 메모리 안전을 저해하지 않고 연속 메모리에 대해서 빠르고 추상적인 접근을 제공함. 
표준라이브러리는 연속적인 저장 공간이 있는 모든 컨테이너 타입에 대해 span 속성을 제공함.
 

 
Span을 사용하는 내내 연속 메모리가 유효하도록 메모리 안전을 유지함.
이렇게 할 경우 메모리 free 이후의 사용과 동시 수정을 포함해 포인터에 내재된 메모리 안전 문제의 정의에서 해방될 수 있음.
이는 런타임 오버헤드 없이 컴파일 시 점검됨.
 

 
예를 들어 원래 컨테이너를 수정하면 추후 span에 대한 접근을 방지하여 수정 후에는 span 변수에 다시 접근할 수 없음.
span은 원래 컨테이너를 능가할 수 없으며, 이를 lifetime dependency라고 부르며 span을 통해 underlying 스토리지에 대한 접근이 가능하면서도 삭제되지 않도록 예방함.
 

 
Swift 6.2는 런타임 버그 없이 더 안전한 동시성 코드를 작성할 수 있도록 도움.
MainActor에서 접근할 경우 데이터 경쟁으로 인해 해당 코드는 문제가 될 수 있음.
병렬 실행을 위한 코드가 필요 없더라도 언어에 암시적으로 작업을 백그라운드에서 오프로드하는 지점이 여러개이기 때문임. 
 
Swift 6.2에서는 이 개념을 바꾸어 동시성 도입을 결정하기 전까지 기본적으로 단일 스레드를 유지함. 
이러한 변경 덕에 Swift 6.2 사용시 기본적으로 데이터 경합 없이도 가장 자연스러운 코드를 작성할 수 있음.
프로젝트에 동시성을 도입하는 더 쉬운 경로를 제공.
 

 
우선 변경 가능한 상태에 대한 비동기 함수 호출이 더 쉬워짐. 
특정 actor에 연결되지 않은 비동기 함수를 열심히 오프로드하는 대신에 해당 함수는 호출을 받은 actor에서 계속 실행됨.
 
비동기 함수에 전달된 값이 actor 밖으로 전송되지 않기 때문에 데이터 경합이 발생하지 않음.
비동기 함수는 구현중인 작업을 오프로드 할 수 있지만 클라이언트는 가변 상태에 대하여 걱정할 필요가 없음.
 

 
또한 MainActor의 Conformance 구현을 더 쉽게 만들었음.
Exportable 프로토콜을 StickerModel이 Conformance 하여 구현하고자 하는데, 내보내기에는 actor에 대한 격리가 요구되지 않기 때문에 에러가 발생함.
언어는 MainActor로 부터 홀출될 수 있는 것으로 가정했고, StickerModel이 MainActor 상태를 사용하지 못하도록 함.
 
Swift 6.2는 이러한 Conformance를 지원하는데, @MainActor 상태가 필요한 Conformance를 Isolated Conformnace라고 부름.
컴파일러는 MainActor Conformance가 MainActor에만 사용되도록 해 안전함.
 

 
MainActor에 보존되는 한 모든 Exportable 타입 배열에 StickerModel을 추가하는 ImageExporter 타입도 생성 가능함.
만약 nonisolted로 변경한다면 컴파일러가 배열에 StickerModel을 추가하는 것을 막음.
MainActor 밖에서 StickerModel에 내보내기를 호출하는 것이 안전하지 않기 때문에임
 

 
전역 및 정적 변수는 가변 상태에 어디서든 접근할 수 있기 때문에 데이터 레이스에 취약함.

 
일반적으로는 전역 상태를 보호하기 위해 MainActor를 사용함.
그리고 모든 가변 상태를 보호하기 위해 MainActor와 함께 전체 클래스에 주석을 다는 것이 일반적임.
 

 
완전히 단일 스레드 형식인 프로그램을 모델링하려면 프로젝트에 있는 모든 것에 @MainActor라고 쓰면 됨.
단일 스레드 코드를 더 쉽게 모델링 할 수 있도록 기본적으로 MainActor로 추론하는 모드를 도입함.
 
MainActor는 기본적으로 모든 가변 상태를 보호하기 때문에 안전하지 않은 전역 및 정적 변수 SDK와 같은 다른 MainActor 기능의 호출 등에 대한 데이터 레이스 안전 오류를 없앰.
 

 
Opt-in이며 앱, 스크립트 및 기타 실행 대상에 권장됨.
작업을 백그라운드로 오프로드 하는 것은 CPU 집약적인 작업을 수행할 때 앱 반응성에 있어서 여전히 중요함.
 

 
extractSubject 메서드는 @concurrent 속성을 활용해 해당 작업을 오프로드할 수 있음.
@concurrent는 함수가 항상 동시 스레드 풀에서 실행되도록 하여 actor의 역할일 비워 동시에 다른 작업을 수행하도록 함.
이러한 언어 변경은 동시성을 더 쉽게 다루도록 함께 동작함.
 
데이터 경합 위험이 없는 MainActor에서 기본적으로 실행되는 코드를 작성하는 것으로 시작
비동기 코드를 작성해보고(여전히 코드는 MainActor에서 실행됨), 성능 향상이 필요한 경우 @concurrent를 통해 병렬로 실행되게 오프로드 할 수 있음.
 

 
Xcode에서 세팅에서 선택사항으로 구성되었음.
 
 
 
 
 
 
 
 
 
 
(참고)
https://www.youtube.com/watch?v=Pvf8OLnAUGI