---
# System prepended metadata

title: ' Swift Macros [1주차] '
tags: ["\U0001F4BB WWDC 스터디"]

---

<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
    @
```