WWDC/Swift

[Swift] WWDC23 - What's new in Swift

유정주 2023. 6. 7. 17:52
반응형

서론

WWDC23의 What's new in Swift를 보고 파파고와 함께 정리했습니다.

WWDC22에서는 한글 자막을 지원했는데 WWDC23에서는 지원을 안 하나봐요..

추후 한글 자막도 추가가 되기를 기원합니다🙏

 

Swift 5.9에서는 매크로가 핵심인듯 했습니다.

이 영상뿐만 아니라 여러 영상에서 언급을 하니 WWDC 23을 보실 계획이라면 꼭 매크로 챕터를 먼저 보셨으면 좋겠습니다.

 

올해 WWDC 영상에서는 챕터를 지원합니다.

따라서 포스팅도 WWDC 영상에서 제공하는 챕터 단위로 정리해보았습니다.

 

 

Swift project update

Swift의 발전을 위해 스위프트 오픈 소스 프로젝트를 시작했다고 합니다.

이제 Swift 포럼에서 새로운 기능이나 중요한 행동 변화(significant behavior changes)가 제안되고 검토되며,

이러한 변화를 보고 싶다면 스위프트 웹사이트 대시보드에서 확인할 수 있습니다.

 

vision 문서를 통해 새로운 제안을 결합하는 방법을 도입했습니다.

처음으로 수락된 내용은 Swift의 macros 기능입니다.

이 기능은 Swift 5.9의 새로운 기능이며 이번 영상의 후반부에서 다룹니다.

 

 

Using if/else and switch statements as expressions

Swift 5.9에서는 if/else와 switch를 이용해 코드를 정리할 수 있습니다.

 

예를 들어, 복잡한 조건을 기준으로 let 변수를 초기화하려면 삼항연산자(?:)를 이용해야 했습니다.

이제는 if문을 이용해 가독성 좋게 작성할 수 있습니다.

 

전역 변수나 저장 프로퍼티를 초기화하는데도 사용할 수 있습니다.

 

기존에는 조건문을 사용해야할 때 즉시 실행되는 클로저를 이용해야 했습니다.

이제는 클로저 없이 바로 if문을 이용해 초기화가 가능합니다.

 

 

Result builders

SwiftUi같은 선언적 구문인 Result Builder(the declarative syntax that drives features like SwiftUI)는 타입 체크 성능, 코드 완성, 오류 메시지 개선 등 상당한 개선이 있었습니다.

 

이전에는 잘못된 코드를 에러라고 판단하는데 오랜 시간이 걸렸는데, 이 부분에 집중해서 개선했다고 합니다.

지금까지는 잘못된 부분에 에러를 표시해주는 상황이 있었습니다.

위 예시는 실제로는 NavigationLink(value: .one)가 문제지만 $0.view에 에러 표시가 되어있습니다.

 

최신 릴리즈에서는 보다 정확히 컴파일러 체크를 받게 됩니다.

 

 

type parameter packs

Generic을 이용해 프레임워크를 어떻게 개선할 수 있는지 알아보겠습니다.

 

스위프트는 거의 모든 곳에 Generic이 포함되어 있습니다.

대표적으로 Array가 있죠.

Array의 원소 타입은 원소의 값에서 유추할 수 있으므로 명시적으로 타입을 지정할 필요가 없습니다.

 

스위프트의 Generic 시스템은 타입 정보 보존을 지원하여 구체(concrete) 타입에서도 코드가 원할하게 작동하게 합니다.

예시를 보겠습니다.

 

evaluate를 이용해 Bool을 입력받아 처리하여 Bool을 return 하고 싶습니다.

 

또한, 여러 인자를 받아 여러 개의 반환 값을 리턴하고 싶습니다.

 

현재는 이를 구현하기 위해 원하는 개수만큼 메서드를 오버로딩해야 합니다.

딱 봐도 한계가 분명함을 알 수 있습니다.

 

Swift 5.9에서는 인자 길이를 추상화하여 정의할 수 있습니다.

이를 type parameter pack 이라고 부릅니다.

 

type parameter pack을 이용하면 개별적인 오버로드가 있는 메서드를 단일 함수로 축소할 수 있습니다.

 

evaluate 함수는 위 코드처럼 축소됩니다.

 

함수는 별도로 request를 처리하여 각 결과를 반환합니다.

따라서 함수 사용을 할 때 type parameter pack 사용 유무를 몰라도 자연스럽게 사용할 수 있습니다.

 

이 변화는 스위프트의 기본 설계 목표 중 하나인 간결한 코드를 통한 명확한 표현을 이루었다고 합니다.

Swift의 고급 기술은 원하는 의미를 쉬운 방식으로 나타낼 수 있게 해준다고 하네요.

 

더 자세한 내용은 WWDC23 - Generalize APIs using parameter packs 에서 다룹니다.

 

 

Swift macros

Swift 매크로를 사용하면 언어 자체의 기능을 확장하여 Swift의 표현을 더 정확히할 수 있습니다.

 

예시를 보겠습니다.

 

위 코드의 조건이 거짓일 경우에는 프로그램이 중지되겠지만, 무엇이 잘못되었는지는 정확히 알 수 없습니다.

XCTest는 조금 더 자세한 정보를 제공하지만 이또한 유의미한 정보는 아닙니다.

a가 잘못되었는지? b가 잘못되었는지? 아니면 결과가 틀린건지 알 수가 없습니다.

 

 

Swift 매크로를 이용하면 이를 개선할 수 있습니다.

해시 문자(#)를 추가하여 assert라는 매크로를 확장합니다

 

이제 프로그램은 각 값과 결과를 표시해줍니다.

 

 

매크로도 패키지로 배포되므로 매크로를 정의하는 모듈을 가져와 접근할 수 있습니다.

위에서 본 assert 매크로는 PoserAssert 라이브러리에서 제공됩니다.

 

인자가 잘못된 경우 에러메시지도 표시되기 때문에 안전하게 코드를 작성할 수 있습니다.

 

 

external 매크로

대부분의 매크로는 외부(external) 매크로로 정의되어 있습니다.

 

 

external 매크로 타입은 컴파일러 플러그인 역할을 하는 별도의 프로그램에 정의됩니다.

Swift 컴파일러가 매크로 호출부를 전달하면 플러그인에서 소스코드를 생성하여 스위프트 프로그램에 통합됩니다.

덕분에 개발자는 보일러 플레이트를 만들지 않아도 됩니다.

 

 

매크로 선언(declaration)

매크로 선언(declaration)에는 추가 역할이 정의되어 있습니다.

여기서 assert 매크로는 독립식 매크로입니다.

해시 구분(#)을 사용하고 해당 구문에서 직접 작동하여 새로운 코드를 생성하기 때문에 프리스탠딩(Freestanding)이라고 합니다.

 

매크로에는 더 다양한 종류가 있으며 이는 우리가 작성하는 여러 보일러 플레이트를 개선해줍니다.

예를 들어 Path를 나타내는 Enum에 절대 경로와 상대 경로를 나타내는 case가 있다고 합시다.

 

이 케이스들로 paths를 필터링할 수도 있겠죠.

 

 

매크로는 이런 보일러플레이트를 줄여줍니다.

CaseDetection 매크로는 프로퍼티 래퍼와 동일한 문법을 사용해 작성되는 첨부(attached) 매크로입니다.

 

이 매크로는 각 case인지 판단하는 프로퍼티 생성 코드를 삽입해줍니다.

 

 

매크로 역할(Rules)

Attached 매크로는 5개의 역할로 나뉩니다.

Path 열거형 예시는 첫 번째인 Member 매크로입니다.

 

 

이 매크로들은 여러 개를 연결하여 더 유용하게 사용할 수 있습니다.

대표적인 예시는 Observation입니다.

객체의 변화를 관찰하려면 객체에 Published를 표시하고 View에 프로퍼티 래퍼를 사용하면 됩니다.

이 단계 중 하나라도 놓치면 UI가 예상대로 업데이트되지 않을 수 있습니다.

 

@Observable 매크로를 사용하면 모든 프로퍼티를 관찰할 수 있기 때문에 하나하나 처리하지 않아도 됩니다.

 

 

Observable 매크로는 세 가지 매크로 역할의 구성으로 동작하며 많은 코드를 삽입합니다.

 

 

매크로 코드 확인

Xcode에서 바로 매크로가 어떻게 확장되는지 확인할 수 있습니다.

 

이 영상에서 다룬 내용은 겉핥기만 한거고,

더 자세한 내용은 WWDC23 - Expand on Swift macros에서 다룬다고 합니다.

또한, 매크로를 직접 작성하는 실습은 WWDC23 - Write Swift macros에서 진행한다고 하네요.

 

 

Swift foundation

 Swift는 확장 가능한 언어로 설계되었습니다.

 Swift 디자인은 읽고 쓰기 쉽고, 명확하면서 간결한 코드를 강조합니다.

Swift의 강력한 기능을 활용하여 SwiftUI, SwiftData 같은 프레임워크를 사용하면 원하는 결과를 빠르게 도달할 수 있습니다.

 

 

Swift는 이러한 고급 기능을 지원하면서도 효율적입니다.

컴파일에서 가비지 컬렉션 대신 value 타입과 reference counting을 사용하여 메모리 공간을 줄일 수 있기 때문입니다.

이는 Swift를 Objective-C로 가능했던 low-level 시스템단으로 넣을 수 있음을 의미하며,

스위프트의 명확한 코드와 타입 안정성을 더 많은 곳에 사용할 수 있음을 의미합니다.

 

최근 스위프트의 Foundtaion 프레임워를 다시 작성하기 시작했습니다.

Apple 플랫폼과 Apple 플랫폼이 아닌 모든 곳에서 Foundation의 single shared implementation으로 이어질 것입니다.

스위프트로 대량의 Objective-C와 C 코드를 다시 작성하는 것을 의미하는데, 이를 통해 많은 성과가 있었습니다.

 

Calendar의 날짜 계산 기능이 Swift의 Value Semantic으로 인해 20% 이상 개선 효과를 냈습니다.

또한 FormatStyle을 이용한 Date formatting은 Formatting 벤치마크에서 150%나 향상된 성능을 보여주었습니다.

 

 

JSON 디코딩도 개선되었습니다.

Foundation은 JSONDecoder 및 JSONEncoder를 위해 Objective-C를 왔다갔다 하는 과정을 제거했습니다.

이를 통해 구현속도가 2배 ~ 5배 개선되었습니다.

 

 

열거형 Date를 호출하는 벤치마크를 예시를 보겠습니다.

벤추라에서는 Objective-C가 Swift보다 더 빨랐지만,

새로운 OS인 Sonoma에서는 Swift가 20% 더 빨라져 Objective-C보다 3ms 더 빠른 결과를 보여줍니다.

 

 

Ownership

Swift 5.9에서는 lower level 제어를 보조하는 새로운 opt-in 기능이 도입되었습니다.

이 기능은 소유권의 개념, 코드가 앱을 통과할 때 값을 소유하는 부분에 초점이 맞춰졌습니다.

 

몇 가지 예제 코드를 보겠습니다.

위 코드에서는 withUnsafeBufferPointer로 low level 시스템을 호출합니다.

하지만 이러한 방식은 close( )를 호출하지 않는 등의 실수가 발생하기 쉽습니다.

 

deinit을 가진 클래스로 만들어서 해결할 수 있는데, 이러면 또다른 문제가 생깁니다.

클래스는 Reference Semanctic이기 때문에 스레드 간에 객체를 공유하게 되어 race condition이나 의도치 않은 상태 공유가 발생할 수 있기 때문입니다.

 

이런 문제는 첫 번째 사진의 구조체 버전도 동일하게 발생합니다.

참조 객체에 접근하여 데이터를 수정하기 때문입니다.

 

Noncopyable structs and enums

Swift 5.9에서는 이 문제를 해결할 수 있습니다.

구조체나 열거형에 ~Copyable을 작성하면 복제가 불가능해집니다.

~Copyable을 작성한 구조체는 deinit을 사용할 수 있고, 이를 통해 close를 호출할 수 있습니다.

 

consuming method

consuming 키워드를 메서드 앞에 붙여 해당 메서드를 최종 호출 메서드로 지정할 수도 있습니다.

최종 호출 메서드가 호출된 후에는 해당 객체를 사용할 수 없습니다.

위 코드에서 close는 최종 호출 메서드가 되었습니다.

 

따라서 close 이후에는 더이상 file 객체를 사용할 수 없습니다.

이는 의도치 않은 상태 공유 등의 문제를 해결해줍니다.

 

 

~Copyable은 Swift의 System 레벨 프로그래밍의 강력한 기능 중 하나로, 아직 초기 단계입니다.

이후 버전의 Swift에서는 Generic까지도 확장되며, Swift 포럼에서 자세한 토의 내용을 확인할 수 있습니다.

 

 

C++ interoperability

지금까지는 Swift에서 C++을 사용하기 위해서는 Objective-C를 거쳐야 했습니다.

Swift 5.9에서는 직접 C++ 타입 및 기능과 상호 작용할 수 있는 기능을 도입했습니다.

 

C++ 코드로 작성된 Person 구조체에는 서로 다른 C++ 타입 변수와 메서드, vector같은 C++ Container가 포함되어 있습니다.

Swift에서는 이 코드에 직접 접근하여 사용할 수 있습니다.

 

반대로 C++에서 스위프트를 사용하는 것은 Objective-C와 동일한 매커니즘을 가집니다.

다만, Objective-C에서는 @objc라는 속성이 달린 Swift 클래스만 사용이 가능했지만, 

C++은 브릿지 오버헤드 없이 대부분의 Swift 타입과 API를 직접 사용할 수 있습니다.

 

 

더 자세한 내용은 WWDC23 - Mix Swift and C++ 또는 Swift 포럼에서 다룬다고 합니다.

 

 

What's new in Swift Concurrency

추상 모델은 크게 Task와 Actor로 나뉩니다.

 

Task는 개념적으로 어디에서나 실행될 수 있는 순차적인 작업 단위를 나타냅니다.

프로그램에서 await가 있을 때마다 일시 중단된 뒤 재시작할 수 있습니다.

 

 

Actor는 격리된 상태에 대한 상호 배타적인 접근을 제공하는 동기화(synchronization) 매커니즘입니다.

외부에서 Actor에 들어가면 Task가 중단될 수 있기 때문에 await이 필요합니다.

 

 

Task와 Actor는 추상적 언어 모델에 통합되지만, 그 모델 내에서는 서로 다른 환경에 맞게 서로 다른 방식으로 구현될 수 있습니다.

 

 

custom actor executors

Swift 5.9에서 커스텀 Actor Executors(custom actor executors)는 특정 Actor가 자체 동기화 메커니즘을 구현할 수 있도록 허용합니다.

이를 통해 Actor는 기존 환경에서 더 유연해질 수 있습니다.

이 예시는 데이터베이스 연결을 관리하는 Actor입니다.

Actor이기 때문에 상호 배타적인 접근을 보장하므로 동시 접근이 불가능합니다.

 

 

동시 접근이 필요한 경우 커스텀 Actor Executors를 사용하면 됩니다.

actor 외부에서 pruneOldEntries 메서드를 await하면, 해당 대기열에서 dispatch-async를 진행합니다.

이러면 개별 actor들이 동기화 제어를 더 유연하게 할 수 있습니다.

 

 

이게 가능한 이유는 DispatchSerialQueue가 SerialExecutor 프로토콜을 채택했기 때문입니다.

 

Concurrency와 관련된 더 자세한 내용은 WWDC21 - Swift Concurrency: Behind the Scenes와 WWDC23 - Beyond the basics of Structured Concurrency. 에서 다룬다고 합니다.

 

 

FoundationDB: A case study

마지막 챕터는 iOS, MacOS 앱과 매우 다른 환경의 Swift에 대한 연구 사례입니다.

FoundationDB는 C++로 작성된 매우 큰 Code base 오픈소스 프로젝트입니다.

C++을 이용한 비동기 프로그래밍 대신 Swift를 이용하면 성능, 안전성, 코드 명확성 등에 이점이 있다는 것을 발견했습니다.

 

이 코드는 C++에는 async/await 없기 때문에 C++ Future 타입을 구현한 코드입니다.

 

 

이를 Swift로 구현하면 더 깔끔하게 구현할 수 있습니다.

async/await을 이용해 구현한 코드입니다.

async/await를 이용해 비동기 처리를 했습니다.

또한 MasterData를 일반적인 클래스 객체처럼 자동으로 Reference Count를 관리할 수 있습니다.

 

 

챕터 정리

Swift 5.9에서는 type parameter packs, 매크로를 이용해 더 나은 코드를 더 빨리 작성할 수 있습니다.

~Copyable을 이용해 Reference Count 오버헤드 없이 리소스를 관리할 수 있게 되었습니다.

C++과 상호 운용이 가능하여 Swift의 이점을 더 많은 코드에 적용할 수 있게 되었습니다.

마지막으로 Swift의 유연한 비동기 모델을 더 많은 환경에서 사용할 수 있게 되었습니다.

 

감사합니다.

 

참고

https://developer.apple.com/wwdc23/10164


아직은 초보 개발자입니다.

더 효율적인 코드 훈수 환영합니다!

공감 댓글 부탁드립니다.

 

 

반응형