스트리밍은 대부분의 브라우저와
Developer 앱에서 사용할 수 있습니다.
-
Swift의 새로운 기능
Swift와 관련된 업데이트를 확인해 보세요. 지난 10년간의 Swift의 역사를 간략히 살펴보고, 커뮤니티가 작업 그룹을 통해 성장해온 과정과 패키지 생태계를 확장하고 플랫폼 지원을 향상한 방법에 대해 알아보세요. 데이터 레이스 안전성을 기본으로 구현하는 새로운 언어 모드, 고도로 제한된 시스템에서 Swift를 실행할 수 있게 해주는 언어 하위 집합을 소개합니다. noncopyable 유형, 유형이 지정된 오류 처리 및 향상된 C++ 상호 운용성 등 언어와 관련된 업데이트도 살펴보세요.
챕터
- 0:00 - Introduction
- 0:12 - Swift over the years
- 3:44 - Agenda
- 3:58 - Swift project update
- 4:08 - Community
- 4:59 - Packages
- 5:50 - Blogs
- 6:33 - Swift everywhere
- 7:37 - Cross compilation to Linux
- 11:27 - Foundation
- 13:06 - Swift Testing
- 14:34 - Improvements to builds
- 16:15 - Swift's new space
- 17:03 - Language updates
- 17:29 - Noncopyable types
- 19:55 - Embedded Swift
- 21:47 - C++ interoperability
- 23:34 - Typed throws
- 26:07 - Swift 6 language mode and data-race safety
- 28:43 - Low-level synchronization primitives
- 29:59 - Wrap up
리소스
- Forum: Programming Languages
- Install Swift
- Swift 6 Migration Guide
- Swift Blog
- Swift Community Overview
- Swift Forums
- The Swift Programming Language
관련 비디오
WWDC24
- 명시적으로 빌드된 모듈 쉽게 이해하기
- Embedded Swift로 경량화하기
- Swift 6으로 앱을 마이그레이션하기
- Swift Testing 소개
- Swift Testing으로 테스트 심화하기
- Swift에서 noncopyable 유형 소비하기
- Swift의 성능 살펴보기
WWDC23
-
다운로드
안녕하세요 ‘Swift의 새로운 기능’에 오신 것을 환영합니다 저는 Mishal이고 나중에 동료인 Meghana가 함께하겠습니다 올해는 Swift 프로젝트의 주요 이정표가 되는 해입니다 WWDC2014에서 프로젝트가 발표된 지 10년째이기 때문이죠
Swift가 발표된 다음 해에는 오픈 소스로 Linux에서도 사용할 수 있게 됐죠 또한 언어와 표준 라이브러리에 대한 커뮤니티 중심의 발전 프로세스도 도입했습니다 2016년에 Apple은 Swift 3와 함께 Swift Package Manager를 발표했습니다 새로운 발전 프로세스를 사용하는 첫 번째 언어 버전이었고 80개 이상의 언어 제안이 포함되었습니다 Swift 2에서 3로 마이그레이션하는 과정을 저희와 함께 하셨다면 어려웠던 것이 기억나실 것입니다 우리는 그 경험을 통해 배웠고 Swift 4에서 모든 Swift 코드를 한 번에 새로운 언어 모드로 옮기지 않고도 새로운 언어 모드를 도입하는 방법을 알아냈습니다 동일한 컴파일러가 여러 언어 모드를 지원할 수 있기 때문에 Swift 3와 Swift 4로 컴파일된 모듈을 동일한 프로그램에서 자유롭게 조합할 수 있습니다 이 새로운 접근 방식을 통해 생태계 전반에 걸쳐 새로운 언어 모드를 점진적으로 도입할 수 있었으므로 모든 개발자는 준비가 되었을 때 마이그레이션할 수 있었습니다 2018년에는 제네릭 시스템을 개선했고, 그 예로는 현재 Swift에서 당연하게 여겨지는 조건부 적합성을 들 수 있죠 이는 또한 가장 중요한 릴리즈 중 하나를 위한 토대를 구성했습니다 Swift 5에서는 Apple 플랫폼에 안정적인 ABI를 도입했습니다 앱 개발자에게 이는 더 작은 다운로드 크기를 의미했습니다 더 이상 앱에서 Swift 표준 라이브러리의 전체 사본을 번들로 구성하지 않아도 되니까요 그 대신에 Swift 표준 라이브러리 자체가 OS의 일부가 되었고 해당 OS에 최적화되고 모든 Swift 앱과 프레임워크에서 공유되었죠 이는 근본적인 변화를 나타냅니다 이제 Swift의 표현 능력을 온전히 활용하여 더 뛰어나고 더 안전한 API와 프레임워크를 빌드할 수 있기 때문이죠 그리고 우리는 SwiftUI의 도입을 통해 이를 해냈는데 Swift의 고유한 기능을 활용하여 UI 앱을 더 잘, 빠르게 빌드하죠 2020년까지 Swift는 더 많은 플랫폼에 제공되었고 Windows로의 커뮤니티 포트가 swift.org에서 공식 제공되었습니다 Apple은 Async/Await, Actors 및 구조화된 동시성이 포함된 주요 기능인 동시성 모델을 도입했습니다
이듬해에는 배포된 Actor를 도입하여 네트워크 서비스를 더 쉽게 빌드할 수 있게 되었습니다 또한 동시성 모델을 계속해서 개선했습니다 같은 해에 커뮤니티에서 VSCode용 Swift 확장 프로그램을 릴리스하여 Swift 개발을 위한 크로스 플랫폼 편집 기능을 제공했습니다
작년에는 C++를 지원하는 양방향 상호 운용성을 도입했죠 덕분에 Swift의 안전성과 표현성을 더 쉽게 가져와서 대규모의 크로스 플랫폼 C++ 코드 기반을 개선할 수 있었죠 또한 매크로를 도입했는데, 이는 반복되는 보일러플레이트를 줄이고 SwiftData 같이 표현력이 더 풍부한 차세대 API를 지원합니다
이렇게 해서 Swift 6까지 왔죠 Swift 6는 이동성과 성능 그리고 전반적인 개발자 경험을 개선합니다 또한 Swift 6 언어 모드도 도입하여 올바른 동시 프로그램을 작성하는 데 도움이 되는 데이터 레이스 안전성을 보장합니다
Swift 프로젝트의 몇 가지 주요 성과와 새로운 투자에 대해 다루고 Swift를 사용할 수 있는 새로운 장소도 살펴보겠습니다 그리고 새로운 언어 기능 몇 가지에 대해 이야기하겠습니다 새로운 언어 모드인 Swift 6를 포함해서 말이죠 Swift 프로그래밍 언어는 는 더 큰 생태계의 일부입니다 이 생태계에는 도구, 패키지 그리고 여러분 같은 개발자가 있는 활기찬 커뮤니티가 포함되어 있죠 이 커뮤니티가 어떻게 발전해 왔는지에 대해 이야기해 보죠 처음에는 Swift Core 팀이 유일한 운영 그룹이었고 언어 발전 프로세스를 비롯해 많은 것을 담당했습니다 커뮤니티가 성장함에 따라 지난 몇 년 동안 운영 그룹과 작업 그룹의 수를 늘렸습니다 올해에는 플랫폼 운영 그룹을 도입해서 더 많은 곳에 Swift를 적용하는 데 집중하고 있습니다 또한 Swift Core 팀은 개발자 경험과 더 넓은 생태계에 중점을 둔 새로운 생태계 운영 그룹을 만드는 작업을 적극적으로 하고 있습니다 하위 수준 환경에 대한 모멘텀을 지속하기 위해 Swift Core 팀은 새로운 내장 작업 그룹을 도입하려는 노력도 하고 있습니다 Swift 커뮤니티에 참여하고 swift.org/community에서 다양한 운영 그룹과 작업 그룹을 살펴보세요 Swift.org는 Swift 프로젝트를 위한 집이라고 할 수 있습니다 웹사이트 작업 그룹은 홈페이지와 시작하기 설명서의 많은 부분을 개선했습니다 이러한 가이드에는 크로스 플랫폼 라이브러리를 비롯한 새롭고 다양한 튜토리얼이 있어서 Swift의 여러 기술을 살펴볼 수 있죠 Swift 패키지를 살펴보려면 swift.org/packages를 방문하세요 swiftPackageIndex.com과 통합되어 있죠 Swift Package Index는 다양한 Swift 버전과 플랫폼의 패키지를 모두 빌드하여 애플리케이션에 적합한 패키지를 선택하는 데 도움이 됩니다 Swift 커뮤니티는 매월 커뮤니티 쇼케이스용 패키지를 선정합니다 좋아하는 패키지를 추천하고 싶다면 forums.swift.org에서 알려주세요 올해의 swift.org 블로그 게시물에서는 Swift 커뮤니티의 흥미로운 개발을 집중 소개했습니다 몇 가지 예를 들겠습니다 Browser Company는 Swift의 상호 운용성을 활용하여 네이티브 UI를 사용하는 Windows 앱을 빌드했습니다 ‘Swift로 GNOME 앱 작성하기’에는 결과 빌더가 어떻게 네이티브 GNOME UI 라이브러리용 선언적 구문을 활성화했는지 나와 있죠 이 블로그 게시물에서는 Swift 6의 새 기능인 팩 반복을 다룹니다 팩 반복은 값 매개변수와 상호 작용하는 프로세스를 간소화합니다 예를 들어 팩 반복을 통해 모든 길이의 튜플에 대한 동등 연산자를 쉽게 구현할 수 있습니다 Swift는 점점 더 많은 플랫폼에 포팅되고 있기 때문에 크로스 플랫폼 언어로서 계속 성장하고 있습니다 Swift는 공식적으로 Apple 플랫폼 Linux, Windows에서 지원됩니다 또한 Swift 커뮤니티를 통해 성장하고 있는 플랫폼이 많습니다 WebAssembly도 그 중 하나죠
올해는 지원되는 Linux 플랫폼을 확대하여 Fedora와 Debian가 포함되었습니다
Xcode는 처음 시작할 때부터 Swift의 기본 IDE였고 여전히 Apple 플랫폼에서의 앱 개발을 위한 기본 IDE입니다 하지만 개발 환경이 다양하기 때문에 Apple은 SourceKit LSP를 개발했습니다 IDE와 편집기에서 Swift 지원을 통합하도록 지원하는 Swift용 언어 서버 구현이죠 커뮤니티가 VSCode Neovim, Emacs 등에서 sourcekit-lsp를 도입하는 건 정말 신나는 일이에요
이렇게 하면 여러분이 선택한 편집기와 플랫폼에서 훨씬 더 쉽게 개발할 수 있죠 크로스 컴파일은 일반적인 개발 사용 사례이고 여러분이 Apple 플랫폼을 위해 개발해 왔다면 이미 크로스 컴파일을 사용하고 있는 것입니다 크로스 컴파일을 사용하면 한 환경에서 실행 파일을 생성하고 이를 다른 환경에서 실행할 수 있습니다 예를 들어 macOS에서 앱을 빌드하고 iPad에서 실행할 수 있죠 이제 우리는 이 기능을 Linux에 도입하고자 합니다 이렇게 하면 익숙한 macOS 환경에서 프로그램을 개발하고 그 프로그램을 Linux 서버 또는 컨테이너에 배포할 수 있죠
macOS에서 Linux로 크로스 컴파일할 수 있는 완전히 정적인 Swift용 Linux SDK를 소개하게 되어 기쁩니다 라이브러리를 정적으로 연결하면 더 이상 프로그램을 실행하기 위해 추가 패키지를 설치할 필요가 없습니다 이 기능이 실제로 어떻게 작동하는지 보겠습니다 고양이 얼굴 이모티콘 하나를 무작위로 반환하는 간단한 REST API가 있는 Swift 패키지를 사용하겠습니다 이 패키지에 대해 자세히 알아보고 싶으면 ‘Swift OpenAPI 생성기 알아보기’를 확인하세요 이 패키지를 macOS에서 빌드하고 정적 Linux SDK를 사용하여 Linux 서버에서 배포하려 합니다 터미널 윈도우 3개가 열려 있습니다 왼쪽에 있는 터미널은 Swift 패키지를 빌드할 곳입니다 이 터미널은 로컬 컴퓨터에 로그인되어 macOS를 실행합니다 오른쪽 상단의 터미널도 로컬 macOS 컴퓨터에 로그인되어 있죠 아래 터미널에는 Linux 호스트에 대한 개방형 SSH 연결이 있죠 먼저 macOS용 서비스를 만들 건데 Swift 빌드를 실행하여 만듭니다
그 결과로 생성된 바이너리는 macOS에서 실행되도록 빌드됩니다 빌드 출력을 검사하여 확인할 수 있죠
오른쪽 상단 터미널을 통해 로컬 컴퓨터에서 이 서비스를 실행할게요
이제 로컬 호스트에서 수신하는 서버에 요청을 하고 요청을 기록하는 로컬 서버를 확인할 수 있습니다
이제 이 서비스를 Linux 서버에서 실행하도록 크로스 컴파일할게요 먼저 완전히 정적인 Swift용 Linux SDK를 설치해야 합니다
SDK가 설치되는 동안 크로스 컴파일에 필요한 플래그를 살펴보죠 swift-sdk 플래그는 빌드 대상인 SDK를 식별합니다 여기에서는 ARM64 Linux 환경에 대해 컴파일하고 musl에 대해 연결하여 정적으로 연결된 바이너리를 생성하려 한다고 명시합니다 이 바이너리는 모든 Linux 컴퓨터에서 실행할 수 있죠 Swift 런타임이 설치되지 않아도요 Swift 빌드 명령에 플래그를 추가하고 빌드를 시작하겠습니다
이번엔 그 결과 생성된 바이너리가 Linux에서 실행되도록 빌드됩니다 빌드 출력을 검사하여 확인할 수 있죠
이것을 Linux 서버에 복사하여 실행해 보겠습니다
이제 Mac에서 Linux 서버에 요청을 할 수 있습니다
잘 작동해서 고양이 얼굴 이모티콘이 생겼습니다
우리는 먼저 macOS에서 macOS 호스트용 서비스를 생성했습니다 그런 다음 완전히 정적인 Swift용 Linux SDK를 사용하여 macOS에서 Linux 호스트로 크로스 컴파일했습니다 이를 통해 정적으로 연결된 바이너리를 생성할 수 있고 추가 런타임을 설치할 필요 없이 이 바이너리를 Linux 컴퓨터에서 실행할 수 있습니다 swift.org/install에서 SDK 미리보기를 다운로드할 수 있어요 이제 Swift의 주요 라이브러리를 자세히 살펴보겠습니다 Foundation은 여러 응용 프로그램의 필수 구성요소로 JSON 디코딩, 날짜 및 시간 형식 지정, 파일 시스템 연산 등을 비롯해 중요한 API를 제공합니다 또한 Apple에서 가장 오래된 프레임워크 중 하나이며 그 역사는 macOS X 초창기까지 거슬러 올라가죠 Swift가 오픈 소스로 제공되었을 때 우리는 이 API가 모든 플랫폼에서 유용할 거라는 것을 알았습니다 그래서 swift-corelibs-foundation 프로젝트를 도입했습니다 그 이후로 언어는 발전했고 이제 모든 플랫폼에서 하나의 통합된 구현을 사용할 수 있게 되었죠 이러한 이유로 기존의 C 및 Objective-C에서 최신 휴대용 Swift로 Foundation을 다시 작성했죠 그 결과는 더 일관되고 품질이 더 높으며 성능이 더 뛰어납니다 새 기능과 개선 사항이 지원되는 모든 플랫폼에 동시에 제공됩니다 Swift 그 자체처럼요 이 Swift 구현은 작년 가을에 iOS, macOS에 처음 제공되었죠 Objective-C 애플리케이션도 이 개선 사항의 이점을 얻었고요 더 좋은 점은 swift-foundation이 오픈 소스라는 것입니다 Apple은 커뮤니티의 기여를 독려하고, 새 API를 추가하기 위한 개방형 발전 프로세스를 갖추고 있습니다 예를 들어 Predicate는 이제 swift-foundation을 통해 Swift 6의 모든 플랫폼에서 사용할 수 있는 API입니다 올해는 정규 표현식에 대한 지원도 얻었습니다 Foundation에 대한 이 새로운 방향을 기대하고 있습니다 새로운 도입과 커뮤니티와의 긴밀한 상호 작용 모두를 말이죠 새로운 프레임워크인 Swift Testing에 대해 이야기해 보죠 이해하기 쉽고 표현력이 풍부하며 유연하고 확장 가능하죠 매크로와 같은 최신 Swift 기능을 활용하고 동시성과 원활하게 통합됩니다 패키지는 크로스 플랫폼을 염두에 두고 오픈 소스로 개발되었습니다 Xcode, VSCode와 같은 여러 IDE와 원활하게 통합되도록 설계되었죠 Swift Testing 라이브러리의 비전은 생태계의 공식적인 기본 테스트 솔루션이 되는 것입니다 Swift 발전 비전 문서에서 전체적인 API 방향을 확인하실 수 있습니다 Swift Testing의 기능 몇 가지를 살펴보겠습니다 테스트를 선언하려면 Test 속성을 함수에 추가합니다 Test 속성에 대한 인수로 맞춤형 표시 이름을 제공할 수 있습니다 그러면 테스트에서 수행 중인 작업을 이해하기가 더 쉽습니다 expect 매크로를 사용해 결과를 충족하는지 확인할 수 있습니다 이 매크로로 간단하거나 복잡한 Swift 표현식을 작성할 수 있죠 Swift Testing으로 태그를 사용해 테스트를 정리, 필터링할 수 있죠 인수를 사용해 여러 입력에 같은 테스트가 중복되지 않게 할 수 있죠 이는 Swift Testing의 기능 중 일부에 불과합니다 더 자세히 알아보고 싶다면 ‘Swift Testing 소개’, ‘Swift Testing으로 테스트 심화하기’를 확인하세요 코드를 테스트하려면 먼저 코드를 빌드해야 하기 때문에 Xcode에서 코드를 빌드하는 방식을 개선했습니다 Swift 코드를 빌드할 때 각 모듈은 다른 모듈에 따라 달라지며 SDK의 모듈에 따라 달라지기도 합니다 Swift 컴파일러가 SwiftUI 같은 모듈을 만나는 경우 해당 모듈의 바이너리 버전을 빌드해야 할 수도 있습니다 이는 묵시적으로 발생하므로 알아차리지 못할 수도 있죠 단발성 둔화를 제외하고요 하지만 많은 작업이 숨겨져 있죠 사용되는 모든 모듈을 빌드해야 하니까요 Objective-C 또는 C++에 작성된 걸 포함해 순서대로요 다른 Swift 모듈이 빌드되면 같은 바이너리 모듈을 재사용하지만 해당 모듈이 준비될 때까지 기다려야 할 수 있습니다 이 때문에 빌드에서 원하는 만큼의 유사성을 얻지 못합니다 또한 디버거가 이 모든 모듈 파일의 자체 버전을 빌드해야 할 수 있죠 이 경우, 디버거에서 처음으로 변수를 인쇄할 때 일시 정지가 오래 지속될 수 있습니다 명시적으로 빌드된 모듈은 묵시적 단계를 명시적 빌드 단계로 전환하고 이는 모듈 빌드가 동시에 수행될 수 있으며 빌드 로그에 명확하게 표시됨을 의미합니다 그 결과 더 예측 가능하고 안정적인 빌드를 얻을 수 있죠 이제 디버거가 바이너리 모듈을 빌드와 공유하여 디버깅이 더 빨라집니다
Xcode 빌드 설정에서 명시적 모듈 빌드를 활성화할 수 있습니다 ‘명시적으로 빌드된 모듈 쉽게 이해하기’에서 자세히 알아보세요
지난 10년 동안 Swift는 아주 많이 성장했습니다 새 친구들을 만나고 독특한 경험을 해왔고, 이제는 자신만의 공간으로 이동할 시간입니다 Swift는 github.com/swiftlang의 새로운 조직으로 이전되고 Swift Project에서 관리할 예정입니다 여기에는 Swift 컴파일러, Foundation 그리고 다양한 Swift 생태계 패키지가 포함됩니다 곧 마이그레이션이 시작되며 swift.org에 세부 사항이 게시됩니다 새로운 공간에서 Swift가 성장하는 것이 기대되네요 언어와 생태계가 발전하는 데 도움을 주셔서 감사합니다 이는 시작에 불과합니다 이제 Meghana가 Swift 6의 멋진 새 언어 기능에 대해 알려 드리겠습니다 올해는 Swift에게 있어 정말 멋진 한 해였습니다 Swift 6는 새 언어 모드를 도입해 데이터 레이스 안전성을 달성하고 Swift의 안전성 보장을 동시 프로그램까지 확대했습니다 또한 Embedded Swift라는 새로운 언어 하위 집합이 있는데 매우 제한된 시스템에서 실행할 수 있죠 이와 함께 Swift 6에는 새로운 개선 사항이 많이 포함되어 Swift가 훨씬 더 나아졌습니다 noncopyable 유형에 대한 이야기로 시작하겠습니다 value 유형, reference 유형 등 모든 Swift 유형은 기본적으로 복사할 수 있습니다 noncopyable 유형은 이 기본 복사 가능성을 억제하여 고유한 소유권을 표현하고 싶은 시나리오에 적절하게 만들죠 예를 들어, 파일과 같은 고유한 시스템 리소스는 복사할 수 없는 구조로 나타낼 수 있습니다 이 구조를 자동으로 닫는 소멸자를 사용해서요 이 표현은 동일한 파일에 여러 작성자가 있는 것과 같은 런타임 문제를 방지합니다 또한 리소스 누출을 방지하는데 자동 정리 없이도 쉽게 구현할 수 있습니다 하지만 이 표현은 여전히 이상적이지 않습니다 생성자는 열린 파일 설명자를 사용합니다 이는 직관적이지 않고 안전하지도 않습니다
파일 열기와 초기화 사이에 프로그램을 종료하는 코드를 넣을 수 있습니다 소멸자는 실행되지 않고 따라서 리소스 누출이 생깁니다 이 문제를 해결할 수 있습니다 파일 이름을 포함하고 파일을 열고, 파일 이름이 유효하면 초기화를 완료하는 실패 가능 생성자를 사용하면 되죠 이 생성자는 noncopyable 파일 유형의 Optional을 반환하며 Optional은 표준 라이브러리의 일반적인 유형입니다 Swift 5.10의 noncopyable 유형에 대한 지원은 구체적 유형으로 제한되었습니다 Swift 6는 모든 일반적인 컨텍스트 및 Optional 같은 표준 라이브러리의 중요한 일반적인 유형에서 noncopyable 유형에 대한 지원을 구현합니다 이를 통해 이제 파일 유형 같은 noncopyable 유형의 실패 가능 생성자를 작성할 수 있습니다 copyable 및 noncopyable 유형을 모두 추상화하는 강력한 기능은 일반적으로 noncopyable 유형의 사용성을 확장합니다 ‘Swift에서 noncopyable 유형 소비하기’에서 자세히 알아보세요 고유한 소유권을 표현하는 것과 함께 noncopyable 유형을 사용하면 성능을 세밀하게 제어할 수 있죠 리소스 제약이 심한 하위 수준 시스템에서는 복사본 비용이 막대할 수 있으며 noncopyable 유형도 적절합니다 하위 수준 시스템은 메모리, 저장 공간 및 런타임 기능의 제약이 있습니다 적은 메모리 공간으로 인해 이러한 시스템에서 프로그래밍할 때는 C와 C++가 주로 선택되었습니다 이제 Swift를 사용할 수 있습니다 Embedded Swift는 Swift의 새로운 언어 하위 세트 및 컴파일 모델로, 고도로 제한된 시스템에서 매우 작은 독립형 바이너리를 생성할 수 있습니다 reflection 및 any 유형과 같은 런타임 지원이 필요한 특정 언어 기능을 끄고 full generics specialization, 정적 연결 같은 컴파일러 기법을 사용하여 적합한 바이너리를 생성합니다 일부 언어 기능을 끔에도 불구하고 Embedded Swift 하위 집합은 ‘완전한’ Swift에 매우 가까우며 관용적이고 읽기 쉬운 Swift 코드를 쉽게 작성할 수 있게 하죠
Embedded Swift를 활용하여 Swift에서 작성된 게임을 이제 Playdate 같은 소형 게임 콘솔에서 실행할 수 있습니다 게임의 바이너리 크기가 고작 몇 킬로바이트에 불과하죠 Embedded Swift는 단순히 재미와 게임에 국한되지 않고 산업용 애플리케이션 빌드에 많이 쓰이는 다양한 ARM 및 RISC-V 마이크로컨트롤러에서 사용할 수 있습니다 Apple Secure Enclave 프로세서에서 Embedded Swift를 사용합니다 Secure Enclave는 주 프로세서와 분리된 격리된 하위 시스템입니다 중요한 데이터를 안전하게 보호하는 역할을 하죠
보안은 이러한 시스템에서 매우 중요하며 Embedded Swift는 Swift의 안전성 보장을 제공합니다 C와 C++로 Swift의 상호 운용성을 갖추고 임베디드 프로젝트에 Swift를 점진적으로 도입할 수 있습니다 자세한 내용은 ‘Embedded Swift로 경량화하기’를 확인하세요
작년에는 C++를 지원하는 양방향 상호 운용성을 도입했죠 Swift와 C++를 직접 상호 운용할 수 있어 원활한 개발자 경험을 제공하고 브리징 비용이 들지 않습니다 Apple은 상호 운용되는 언어 기능을 계속 확대하고 있습니다 그리고 Swift 6를 사용하면 C++ 가상 메소드, 기본 인수, move-only 유형 및 중요한 C++ 표준 라이브러리 유형을 Swift로 바로 가져올 수 있습니다 상호 운용성에는 유사한 언어 개념 매핑과 시맨틱에 일치하도록 필요한 조정을 하는 것이 포함됩니다 C++ 가상 메소드와 기본 인수는 상응하는 Swift 버전에 매핑되어 있습니다 Person 유형과 같은 C++ move-only 유형은 Swift의 noncopyable 유형에 매핑되어 있습니다 Swift 컴파일러는 필요한 경우 C++ move 생성기에 대한 호출을 삽입합니다 실수로 noncopyable 값을 복사하려고 하는 경우 Swift 컴파일러가 이를 진단합니다 C++는 널리 사용되는 프로그래밍 언어이지만 안전성 보장이 부족하여 보안 공격에 노출되어 있습니다 C++ 프로젝트에 Swift를 점진적으로 도입하여 보안과 생산성을 개선할 수 있습니다 Mac에서는 이제 Finder가 C++ 상호 운용성을 사용합니다 Browser Company는 이를 사용하여 Windows용 ARC 브라우저를 제공하죠 Swift Godot은 이를 통해 Swift 브리징을 Godot 게임 엔진에 제공하죠 C++는 대규모 언어이며 그 상호 운용성은 계속 발전하고 있죠 swift.org에서 최신 정보를 확인하실 수 있습니다 C++ 상호 운용성 관련 자세한 내용은 ‘Swift와 C++ 혼합하기’를 시청하세요 Swift는 예외 조건에서 코드를 실행할 때 오류를 전달, 전파, 포착하는 최고 수준의 오류 처리를 지원합니다 오류는 오류 프로토콜을 따르고 사용자는 throws 키워드를 사용해 전달 함수를 작성할 수 있습니다 전달된 오류는 type erased이고 catch 핸들러의 any Error 유형과 함께 표시됩니다 Type erasure를 사용하면 오류의 구체적인 유형 정보가 손실되므로 동적 유형 확인을 삽입해야 할 수도 있습니다 드물지만 오류를 철저하게 처리하고 싶은 경우도 있죠 Type erasure에는 boxing과 unboxing도 포함되어 있습니다 런타임 할당 기능이 없는 매우 제한된 시스템에서는 이로 인해 어려움이 생길 수 있죠 Swift 6는 이를 해결하기 위해 typed throws를 도입했습니다 Typed throws를 사용하면 오류 유형과 함께 throws 키워드를 지정할 수 있습니다 type erasure가 포함되지 않고 catch 블록에 오류와 그 구체적인 유형이 표시되죠 Typed throws는 Apple의 오류 처리 시스템의 일반화입니다 Untyped throws는 any Error 유형의 typed throws와 같습니다 비전달 함수는 Never 유형의 typed throw가 있는 함수와 동일합니다 typed throws로 구현된 이 공식을 사용하면 일반적인 방식으로 오류 유형을 처리할 수 있습니다 예를 들어 지도 함수는 전달할 수 있는 클로저를 사용하고 클로저를 해당 요소에 매핑합니다 Typed throws를 사용하면 지도 함수가 Failure 유형에 일반적으로 작성되어 전달 및 비전달 케이스에 대한 추상화를 수행하죠 이렇게 하면 코드 중복을 방지하고 정확한 API 계약을 지정할 수 있죠 Typed throws는 API 계약에서 failure 유형을 지정하기 때문에 API의 발전에 제약이 생깁니다 전달된 오류 유형을 변경하는 유연성을 유지하고 싶다면 Untyped throws를 계속 사용하세요 typed throws는 내부 함수 또는 인수로부터 오류를 전파하는 함수로 작업하거나 untyped throws의 비용이 너무 큰 제한된 환경에서 작업하는 경우에 사용합니다
Typed throws 및 지금까지 알아본 다른 업데이트와 함께 Swift 6 컴파일러에는 몇 가지 언어 개선 사항이 더 있으며 성능과 강력함에 대한 내부적인 개선도 이루어졌습니다 이 모든 것 외에도 Swift 6 컴파일러의 새로운 Swift 6 언어 모드는 데이터 레이스 안정성을 기본적으로 달성하죠 데이터 레이스는 동시 프로그램 작성 시 흔히 발생하는 프로그래밍 오류입니다 여러 스레드가 데이터를 공유하는 데 그중 한 스레드에서 데이터를 변형하려고 할 때 발생하죠 데이터 레이스로 인해 예기치 않은 런타임 동작과 프로그램 충돌, 재현하기 어려운 문제가 발생할 수 있습니다 Swift가 시작된 이후로 데이터 레이스 안전성은 Swift 동시성의 주요 목표였으며 이 목표를 달성하기 위해 점점 더 진보해 왔습니다 Swift 동시성은 데이터 격리 달성을 위한 메커니즘, 가변 상태를 보호하기 위한 Actor, 안전한 데이터 공유를 위한 Sendable 중심으로 설계됐죠 Swift 5.10은 완전한 동시성 확인 플래그를 통해 데이터 레이스 안전성을 달성했습니다 새 Swift 6 언어 모드는 기본적으로 데이터 레이스 안전성을 달성하고 앱의 모든 데이터 레이스 문제를 컴파일 시간 오류로 전환합니다 앱의 보안을 크게 향상하고 시간이 촉박한 디버깅 문제를 줄여주죠 새로운 언어 모드를 사용하여 코드를 조정해야 할 수도 있으므로 준비가 되면 이 모드를 채택할 수 있습니다 이를 모듈별로 도입하고 Swift 6 언어 모드로 마이그레이션 했거나, 아직 하지 않은 종속 부분과도 상호 운용할 수도 있죠 데이터 레이스 안전성은 Swift 6 언어 모드 활성화를 통해 이루어지는 유일한 업데이트입니다 다른 모든 업데이트는 Swift 6 컴파일러를 업데이트할 때 기본적으로 사용할 수 있죠 데이터 레이스 확인도 크게 개선되었습니다 안전을 위해 Swift 5.10의 완전한 동시성 확인은 Actor 분리 경계에서 Sendable이 아닌 모든 값을 전달하는 것을 금지했습니다 Swift 6는 원래 분리 경계에서 더 이상 참조될 수 없는 상황에서 Sendable이 아닌 값을 전달하는 게 안전하다는 걸 인식할 수 있습니다 예를 들어 MainActor의 Sendable이 아닌 클라이언트 참조를 ClientStore Actor로 전달하면 컴파일러 경고와 함께 Swift5.10의 완전한 동시성 확인이 함께 발생합니다 하지만 클라이언트 참조는 ClientStore Actor로 전송된 후에 더 이상 MainActor에서 참조되지 않습니다 MainActor와 ClientStore Actor 간에 클라이언트의 상태를 공유하지 않기 때문에 데이터 레이스가 있을 수 없습니다 Swift 6의 데이터 레이스 확인 기능이 개선됨에 따라 성공적으로 컴파일됩니다 클라이언트 참조를 ClientStoreActor에 전달한 후에 도입하면 컴파일러가 데이터 레이스를 나타내는 오류를 표시합니다 Actor에서 제공하는 상위 수준의 동기화 모델 외에도 Swift 6에는 몇 가지 새로운 하위 수준 프리미티브가 있습니다 동기화 모듈에는 Atomic이 있습니다 이는 플랫폼에서 효율적인 lock-free 구현을 제공하는 모든 유형에 대해 일반적입니다 안전한 동시 접근을 위해 Atomic 값은 항상 ‘let’ 속성 안에 저장되어야 합니다 Atomic에 대한 모든 연산은 명시적이며 C 및 C++ 메모리 모델과 유사한 메모리 순서 인수를 사용합니다 동기화 모듈에는 Mutex도 있습니다 Atomic과 마찬가지로 Mutex는 let 속성 안에 저장되어야 하고 안전하게 동시 접근할 수 있습니다 저장소에 대한 모든 접근은 Mutex가 withLock 메소드에 전달된 클로저를 통해 보호하며 이를 통해 상호 배타적인 접근을 보장합니다
점진적 마이그레이션용 인프라와 향상된 데이터 레이스 확인 그리고 동기화를 위한 새로운 하위 수준 프리미티브를 통해 Apple은 데이터 레이스 안전성 달성에 필요한 모든 걸 갖췄습니다 마이그레이션에 대한 모범 사례는 ‘Swift 6으로 앱을 마이그레이션하기’의 대화식 튜토리얼을 따르세요 새롭고 향상된 언어 기능과 중요한 안전 보장 그리고 Swift를 위한 새로운 길까지, 많은 내용을 다루었습니다 swift.org에서 저희와 함께 Swift의 향후 10년을 이끄세요 시청해 주셔서 감사합니다 행복한 코딩하세요
-
-
9:15 - Swift Build
swift build
-
9:20 - Inspecting the build output
file .build/debug/CatService
-
9:24 - Run the REST API service
.build/debug/CatService
-
9:30 - Make a request to REST API service
curl localhost:8080/api/emoji
-
9:45 - Install the Fully static Linux SDK for Swift
swift sdk install ~/preview-static-swift-linux-0.0.1.tar.gz
-
10:18 - Swift build command flag to cross compile
swift build --swift-sdk aarch64-swift-linux-musl
-
10:30 - Inspecting the build output
file .build/debug/CatService
-
10:35 - Copy the service over to our Linux server and run it
scp .build/debug/CatService demo-linux-host:~/CatService ./CatService
-
10:45 - Make a request to REST API service from macOS to Linux
curl demo-linux-host:8080/api/emoji
-
13:50 - Swift Testing - Declare a test function
// Swift Testing import Testing @Test func rating() { let video = Video(id: 2, name: "Mystery Creek") #expect(video.rating == "⭐️⭐️⭐️⭐️") }
-
13:55 - Swift Testing - Customize a test’s name
// Swift Testing import Testing @Test("Recognized rating") func rating() { let video = Video(id: 2, name: "Mystery Creek") #expect(video.rating == "⭐️⭐️⭐️⭐️") }
-
14:13 - Swift Testing - Organize test function with tags
// Swift Testing import Testing @Test("Recognized rating", .tags(.critical)) func rating() { let video = Video(id: 2, name: "Mystery Creek") #expect(video.rating == "⭐️⭐️⭐️⭐️") }
-
14:19 - Swift Testing - Parameterize test with arguments
// Swift Testing import Testing @Test("Recognized rating", .tags(.critical), arguments: [ (1, "A Beach", "⭐️⭐️⭐️⭐️⭐️"), (2, "Mystery Creek", "⭐️⭐️⭐️⭐️"), ]) func rating(videoId: Int, videoName: String, expectedRating: String) { let video = Video(id: videoId, name: videoName) #expect(video.rating == expectedRating) }
-
17:50 - Noncopyable types
struct File: ~Copyable { private let fd: CInt init(descriptor: CInt) { self.fd = descriptor } func write(buffer: [UInt8]) { // ... } deinit { close(fd) } }
-
18:12 - Noncopyable types
guard let fd = open(name) else { return } let file = File(descriptor: fd) file.write(buffer: data)
-
18:42 - Noncopyable types
struct File: ~Copyable { private let fd: CInt init?(name: String) { guard let fd = open(name) else { return nil } self.fd = fd } func write(buffer: [UInt8]) { // ... } deinit { close(fd) } }
-
22:29 - C++ Interoperability
struct Person { Person(const Person&) = delete; Person(Person &&) = default; // ... };
-
22:34 - C++ Interoperability
struct Developer: ~Copyable { let person: Person init(person: consuming Person) { self.person = person } } let person = Person() let developer = Developer(person: person)
-
22:40 - C++ Interoperability
struct Developer: ~Copyable { let person: Person init(person: consuming Person) { self.person = person } } let person = Person() let developer = Developer(person: person) person.printInfo()
-
23:43 - Untyped throws
enum IntegerParseError: Error { case nonDigitCharacter(String, index: String.Index) } func parse(string: String) throws -> Int { for index in string.indices { // ... throw IntegerParseError.nonDigitCharacter(string, index: index) } } do { let value = try parse(string: "1+234") } catch let error as IntegerParseError { // ... } catch { // error is 'any Error' }
-
24:19 - Typed throws
enum IntegerParseError: Error { case nonDigitCharacter(String, index: String.Index) } func parse(string: String) throws(IntegerParseError) -> Int { for index in string.indices { // ... throw IntegerParseError.nonDigitCharacter(string, index: index) } } do { let value = try parse(string: "1+234") } catch { // error is 'IntegerParseError' }
-
24:39 - Typed throws - any and Never error types
func parse(string: String) throws -> Int { //... } func parse(string: String) throws(any Error) -> Int { //... } func parse(string: String) -> Int { //... } func parse(string: String) throws(Never) -> Int { //... }
-
28:02 - Passing a NonSendable reference across actor isolation boundaries
class Client { init(name: String, balance: Double) {} } actor ClientStore { static let shared = ClientStore() private var clients: [Client] = [] func addClient(_ client: Client) { clients.append(client) } } @MainActor func openAccount(name: String, balance: Double) async { let client = Client(name: name, balance: balance) await ClientStore.shared.addClient(client) }
-
28:52 - Atomic
import Dispatch import Synchronization let counter = Atomic<Int>(0) DispatchQueue.concurrentPerform(iterations: 10) { _ in for _ in 0 ..< 1_000_000 { counter.wrappingAdd(1, ordering: .relaxed) } } print(counter.load(ordering: .relaxed))
-
29:21 - Mutex
import Synchronization final class LockingResourceManager: Sendable { let cache = Mutex<[String: Resource]>([:]) func save(_ resource: Resource, as key: String) { cache.withLock { $0[key] = resource } } }
-
-
찾고 계신 콘텐츠가 있나요? 위에 주제를 입력하고 원하는 내용을 바로 검색해 보세요.
쿼리를 제출하는 중에 오류가 발생했습니다. 인터넷 연결을 확인하고 다시 시도해 주세요.