관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] 5. WWDC2023 정리 - Swift 매크로 개념 (Swift Macro, SwiftSyntax, Swift 5.9) 본문

WWDC 정리/WWDC 2023 정리

[iOS - swift] 5. WWDC2023 정리 - Swift 매크로 개념 (Swift Macro, SwiftSyntax, Swift 5.9)

jake-kim 2023. 6. 10. 01:21

Swift 매크로란?

  • Swift 5.9에서 도입
  • Swift 언어로 매크로를 쉽게 사용할 수 있는 것
    • 매크로란? 매크로는 코드 조각을 정의하여 여러 곳에서 재사용할 수 있게 해주고 보통 전처리기에서 생성
    • 전처리기란? 전처리기는 소스코드를 컴파일 하기 전 단계인 전처리 단계에서 수행해주는 것
  • Swift 매크로가 있는 이유 - 컴파일 시간에 반복 코드를 생성할 수 있고 코드를 읽기 쉽게 만들 수 있음

ex) Swift 매크로를 이용하여 중복코드 단순화하기

  • 예제 코드) 튜플 형태인 배열이 있는데 이 튜플에서 첫번째 값은 Int, 두번째 값은 String인 형태
    • 중복코드형태이고 연산에 있어서 실수하기 쉬운 코드

  • Swift5.9 에서 나오는 Swift 매크로를 사용하여 단순화한 형태
    • 컴파일 타임에 정해지고, 중복코드가 많이 개선됨

매크로 사용 방법

  • 매크로 정의
    • 함수 형태와 유사하게 앞에 macro 키워드를 사용

swift macro 사용 방법

  • 매크로 표현식의 인수가 매크로의 매개변수와 일치하지 않거나 입력을 잘못하면 컴파일러는 매크로 확장을 적용하지 않고 오류를 발생

컴파일 에러 예시

  • 이 매크로를 이용하는 쪽에서는 #을 붙여서 사용

#을 붙여서 사용

  • 매크로 구현부는 매크로 플러그인에서 작성

매크로 플러그인

  • 스위프트 매크로를 구현하는 부분
  • 트리 - 노드 구조로 표현
    • pound - 매크르롤 정의한다는 의미
    • identifier("stringify") - 매크로의 이름
    • leftParen, rightParen에서는 각 매크로의 동작을 표현

매크로 플러그인

  • 스위프트 매크로의 가장 좋은점?
    • macro 구현 자체가 Swift로 작성된 프로그램이며 원하는 구문 트리로의 변환을 수행 가능

코드로 보는 매크로 구현 방법

  • Xcode > New file > Swift Macro 선택

  • WWDC라는 이름의 Swift Macro를 생성하면 템플릿 코드와 함께 생성

  • 코드상에서 매크로의 구현이 어떻게 되어있는지 확인하기도 매우 용이
    • Expand Macro 선택

(Expand Macro 선택 시 구현부가 노출)

  • Swift Macro는 deterministic 트리 형태로 되어있기 때문에 테스트하기도 매우 용이
    • Swift Macro 테스트 방법은 WWDC2023 09:10 참고

Macro의 종류

  • 매크로 선언 시 property wrapper로 사용되는 종류는 아래와 같이 여러개가 존재

ex) @attached(member): 연결된 유형의 새 member를 추가하는 것

Swift Macro로 중복 코드 단순화하기

ex) 기울기 값을 가지는 Slope모델과, 낮은 기울기 값을 가지는 EasySlope 모델이 있는 상태

  • 참고) Swift Macro를 정의할때 문자열로 정의해주는 부분이 있어서 테스트 코드와 함께 작성하는것을 추천 (아래 예제에서는 편의를 위해 테스트 코드는 작성 x)
  • EasySlope에서는 Slope를 받아서 초기화하는 부분이 있고 이 안에는 slope라는 computed property가 있는데, 초기화 하는 부분과 slope computed property안에 동일한 코드가 있어서 코드 중복이 있는 문제점이 존재

  • Xcode > New file > Swift Macro 템플릿 생성
  • macro 선언

  • 구현부에서는 Slope안에 있는 Macro를 정의
    • SlopeSubsetMacro는 위에서 있던 EasySlope 부분에 사용될것이므로, Slope안에 EasySlope이 있는 개념이므로 subset 용어를 사용

  • 선언된 enum을 가져오기

  • lldb를 통해 enumDecl 값을 출력해보면, 트리 - 노드 구조로 표현된 부분 확인이 가능
    • 구문 트리 구조를 분석하기 위해서 Macro 실행중에 break point를 두고 lldb에서 node를 인쇄하여 코드를 작성할 것

  • 위 트리-노드 구조를 보고 enum의 case들에 모두 접근

  • InitializerDeclSyntax를 사용하여 init 구문을 만드는 매크로를 만들고, 위에서 얻은 elements를 for-loop돌면서 case 항목 표현식을 작성
    • 핵심) InitializerDeclSyntax, SwiftExprSyntax, SwitchCaseSyntax에 모델의 구조를 String 형태로 넣으면서 만드는 것
    • Syntax 관련 코드는 SwiftSyntax모듈을 import하여 사용

매크로로 작성된 부분

  • 사용하는쪽)
    • 위에서 만든 스위프트 매크로를 EasySlope모델에 적용하기 위해, @SlopeSubset으로 선언하면 컴파일 에러가 발생
    • 매크로에서 이미 선언되었으므로 중복 코드라고 에러가 발생하는것

  • EasySlope안에 있는 init을 삭제하면 완성

  • @SlopeSubset 오른쪽 클릭 > expand macro를 클릭하면 어떻게 정의되어 있는지 한번에 확인도 가능

(해당 예제에서는 init만 적용하고, computed property인 slope에 매크로 적용하는 것은 생략)

위 예제에서 Swift Macro로 변경하기 요약

  • Swift Macro 패키지로 쉽게 생성이 가능
  • EasySlopes유형에서 반복적인 코드 작성 필요 없이 Type Safety함을 얻을 수 있음
  • 구문 트리 구조를 분석하기 위해서 Macro 실행중에 break point를 두고 lldb에서 node를 인쇄하여 코드를 작성
    • 분석한 결과를 토대로 SwiftSyntax모듈에서 제공해주는 매크로 형태로 작성
  • (주의할점은 테스트 케이스를 작성하여 계속 체크해야함)

enumDecl 생성을 실패했을때 처리 추가

  • enumDecl의 guard문안에 TODO 부분 처리

매크로로 작성된 부분

  • SlopeSubsetError.onlyApplicableToEnum과 같이 특정 에러를 정의하고 이를 throw해주면 사용하는쪽에서 쉽게 파악이 가능

사용하는쪽) struct에 잘못 사용한 경우 - 위에서 throw로 던진 에러가 표출

* 참고

https://developer.apple.com/videos/play/wwdc2023/10166/

Comments