<h1><center> Swift Macros [1주차] </center></h1> ###### tags: `💻 WWDC 스터디` > [color=#724cd1][name=데릭] > [Platforms State of the Union - wwdc2023](https://www.youtube.com/watch?v=sby0V96sF7s) > WWDC 2023 Session 중 하나인 `Swift Macros`에 대해 알아보자 ## 개요 Swift Macros를 도입하여 더 쉽고 올바르게 사용할 수 있는 새로운 종류의 API를 잠금 해제? - 매크로는 Swift 방식으로 수행되는 것 > 매크로는 코드 구조를 사용하여 프로젝트와 함께 빌드된 새 코드를 생성하는 주석이다. ```swift @CaseDetection enum Topic { case diversity case mentorship var isDiversity: Bool { if case .diversity = self { true } else { false } } var isMentorship: Bool { if case .mentorship = self { true } else { false } } } ``` - 매크로는 코드에 속성으로 첨부되거나 해시 기호가 있는 독립형일 수 있다. ```swift @CaseDetection enum Topic { case diversity case mentorship } #assert(x == y - 1) ``` 매크로는 API가 언어의 일부인 것처럼 느끼게 하며 주석만으로 새 API를 사용할 수 있는 많은 방법들이 있다. 매크로는 생성된 코드가 프로젝트의 일부인 것처럼 느껴지는 생명력을 얻는다. # 예제 > 유효한 URL 문자열을 확인하는 URL Macro를 만든다 ```swift import Foundation import MyCoolMacros enum Topic { case diversity case mentorship var url: URL { switch self { case .diversity: #URL("https://www.swift.org/diversity/") URL(string: "https://www.swift.org/diversity/")! case .mentorship: #URL("https://www.swift.org/mentorship") } } } ``` - 매크로는 Swift 코드를 생성하기 때문에 Xcode의 `Expand Macro`기능을 사용하여 정확히 무엇을 하는지 볼 수 있다. case .diversity를 보면 URL 이니셔라이져를 호출하고 결과를 강제로 언랩핑한다. **그러나** URL 매크로는 그 이상을 수행한다. **컴파일 타임에서 문자열이 유효한 URL인지 확인할 수 있다.** 예를 들어, URL에는 공백이 있을 수 없으므로 공백을 추가하면 매크로가 사용자 지정 오류 메시지를 제공하여 문자열에서 공백을 자동으로 제거하는 수정 프로그램을 제공한다. -> 이렇게 하면 내 앱이 실행 중일 때 오류가 발생했을 수 있는 상황을 방지하고 코드를 작성할 때 실수한 내용을 바로 수정할 수 있다. 모든 매크로에는 올바른 코드를 작성하는 데 도움이 되는 사용자 지정 피드백 기능이 있다. ```swift import Foundation import MyCoolMacros struct SwiftWebsite { func fetchContent(_ topic: Topic, completion: @escaping (Result<String, Error>) -> Void) { let task = URLSession.shared.dataTask(with: topic.url) { ... } task.resume() } } let website = SwiftWebsite() let task = Task { var content: String? = "" website.fetchContent(.diversity) { result in if case .success(let result) = result { content = result } } if let content { print(content) } } await task.value ``` 비동기 작업을 수행 완료하고 핸들러를 사용하는 fetchContent라는 함수가 있지만 async/await를 사용하고 싶다면 어떻게 해야 할까? - fetchContent 함수를 구현하는 대신 AddAsync 매크로를 연결할 수 있다. ```swift @AddAsync func fetchContent(_ topic: Topic, completion: @escaping (Result<String, Error>) -> Void) { let task = URLSession.shared.dataTask(with: topic.url) { ... } task.resume() } ``` 이제 fetchContent를 호출할 때, CompletionHandler를 전달하는 대신 결과를 기다릴 수 있다. ```swift let task = Task { let content = try? await website.fetchContent(.diversity) if let content { print(content) } } ``` 비동기 함수를 실행하면 Xcode가 Source Editor에서 바로 매크로를 확장합니다. ```swift func fetchContent(_ topic: Topic) async throws -> String { try await withCheckedThrowingContinuation { continuation in fetchContent(topic) { returnValue in switch returnValue { case .success(let value): continuation.resume(returning: value) case .failure(let error): continuation.resume(throwing: error) } } } } ``` Swift는 오픈 소스로 개발되었기 때문에 개발자는 이미 매크로를 사용하여 Assertion 실패에 대한 설명을 자동으로 생성하고 사용자 지정 가능한 기본 프로토콜 적합성을 제공하는 등 가장 일반적으로 요청되는 일부 언어 기능을 구축하고 있다. ```swift #assert @CustomCodable @ ```