일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- Protocol
- uitableview
- 리펙터링
- Observable
- tableView
- Refactoring
- 클린 코드
- 스위프트
- 리팩토링
- collectionview
- UITextView
- ios
- clean architecture
- SWIFT
- 애니메이션
- swift documentation
- rxswift
- Clean Code
- UICollectionView
- Human interface guide
- HIG
- MVVM
- combine
- Xcode
- 리펙토링
- swiftUI
- ribs
- map
- RxCocoa
- uiscrollview
- Today
- Total
김종권의 iOS 앱 개발 알아가기
[iOS - swift] 9. WWDC2023 정리 - (1) Swift Macro의 expansion (Macro의 목적, Macro 모델, 본문
[iOS - swift] 9. WWDC2023 정리 - (1) Swift Macro의 expansion (Macro의 목적, Macro 모델,
jake-kim 2023. 6. 15. 01:54(1). Swift Macro의 expansion (Macro의 목적, Macro 모델, Macro Role 이해하기, @freestanding, @attached)
(2). Swift Macro의 expansion (Macro 구현 방법, 올바른 Macro 작성 방법)
Swift Macro의 목적
- 반복되는 코드 부분의 Boilerplate를 줄이기
- 컴파일러를 수정하지 않고 Swift 패키지에 배포할 수 있는 방식
Swift Macro 4가지 목적
- 일반적으로 C Macro를 사용할 때, side effect, 디버깅 정보 제한 등과 같은 단점들이 존재하는데, Swift Macro에서는 이를 보완하여 장점을 많이 살림
- Swift Macro는 다른 언어에서의 매크로와 다른 방법으로 4가지 목적을 가지고 탄생
- 1) 매크로를 사용할 때 매우 명확해야 한다는 점 (#기호와 @기호를 이용하여 사용)
- # 기호나 @ 기호를 사용 각각 다른 의미를 지니는데 이처럼 여러가지 역할에 따라 기호를 다르게 사용
- 2) macro를 사용할때 실수를 했다면, 컴파일 에러를 보여주어 실수를 쉽게 확인할 수 있어야함
- 3) macro 확장이 예측 가능하고 부가적인 방식으로 프로그램에 통합되어야함
- ex) 아래 코드에서 #someUnknownMacro()는 무엇을 하는지 모른다고해도 아래 finishDoingThingy() 호출을 멈추거나, 중간에 return과 같은 행위를 하여 중간에 block을 탈출하는 일이 없음
- 즉, 매크로를 사용하면 예측 가능한 코드 유지가 가능
- 4) macro 구현부를 Xcode에서 바로 확인할 수 있어야함 (생산성)
- 오른쪽 마우스 > expand macro 클릭 > dimmed 영역과 함께 구현보가 노출됨
- break point도 단계별로 실행이 가능
매크로가 수행되는 방법
- 한 예로 Swift 패키지 플렛폼의 #stringify 매크로가 호출되면, Swift Compiler는 해당 매크로에 대한 구현이 있는 Compiler plugin으로 해당 매크로를 달라는 형태로 요청
- Compiler plugin은 보안 sandbox 별도의 프로세스로 실행
- Compiler plugin은 매크로 사용을 처리하고 매크로에 의해 생성된 새로운 코드 조각인 "expansion"을 반환
- Swift compiler에서 expansion을 받으면 Swift compiler가 expansion을 프로그램에 추가하고 코드의 확장을 함께 컴파일
Macro roles
- 매크로에 대한 일련의 규칙
- 독릭형 매크로 2가지 - expression, decleration
- @freestending(expression): 표현식(실행하고 결과를 생성하는 코드 단위)
- 첨부된 매크로를 생성 5가지 - peer, accessor, memberAttribute, member, conformance
- 두 개의 독립 역할을(@freestanding) 제외한 모든 역할 조합이 가능
freestanding(expression) 개념
- 코드의 '조각'을 리턴하는 독립형 매크로
- 독립으로 사용하는 *표현식
- *표현식: 실행하고 결과를 생성하는 코드 단위
- 아래 코드에서 (x + width)도 하나의 표현식이고, x +, width도 각각 표현식
- 예시) unwrap이 필요할 때 guard를 사용하면, 코드가 단순해지지 않고 긴 내용의 메시지가 들어가는 상황이라 macro를 사용하여 해결
- 값을 계산하고 반환하기를 원하므로 freestanding(expression)를 생성
- 사용하는쪽에서는 #unwrap으로 심플하게 접근
@freestanding(declaration) 개념
- 하나 이상의 프로퍼티나 함수를 붙이는 독립형 매크로
- ex) 2D 배열 유형이 필요한 일종의 통계 분석을 작성할 때, 1차원 배열로 바꾸고 다시 1차원 인덱스를 계산하려고 하는 요구사항에서 사용
(macro없이 사용된 경우)
(3D 배열에서 동일한 요구사항이 나온 경우 위 처리와 비슷한 코드가 생성)
(4D, 5D, ... ND 모두 비슷한 식이 필요)
- makeArrayND라는 macro를 사용
- makeIndex라는 메소드, subscript라는 메소드등을 확장하기 위해서 @freestanding(declaration)을 선언
- 아래와같이 확장성있게 사용할 수 있는 형태
(macro expansion)
@attached(peer) 개념
- 특정 선언에 첨부되는 매크로
- declaration을 검사하고 내부 이름, 타입, 기타 정보에 접근이 가능
- method나 property에서 사용하면 해당 유형의 멤버가 생성
ex) concurrency를 안쓰는곳에 concurrency 지원을 하는 경우, onCompletion 파라미터를 받고 콜백에서 await를 호출해주는 방식으로 구현된 형태
- 사용하는쪽에서 이러한 작업을 많이 수행하고 있기 때문에 macro로 전환하면 편리
- @attached(peer) 매크로를 사용하고 이 매크로 안에서 async, await 버전의 메소드를 연결
- 사용하는쪽에서 메소드 위에 매크로를 선언하여 간편하게 사용 가능
(구현부)
@attached(accessor)
- property에 get, set, willSet, didSet과 같은 접근자를 추가하는 매크로
ex) Person안에는 Dictionary가 있고 이 값은 name, height, birthDate값만 보관하며 나머지 값은 보존만 되는 형태
- 이 코드에서는 getter, setter가 중복으로 여러곳에서 사용되고 있는 형태
- @attached(accessor) 매크로 생성
- 사용하는쪽
(expand macro)
@attached(memberAttribute) 개념
- 새로운 type이나 extension을 추가하는 것
ex) Person 구조체 안에 특정 프토토콜을 준수하도록 하고 싶은 경우
- cf) macro를 여러개 동시에 사용이 가능 - 두 개의 독립 역할을(@freestanding) 제외한 모든 역할 조합이 가능
구현부) @attached(memberAttribute)를 사용하여 Person 구조체에 DictionaryRepresentable을 준수하도록 선언
- @attached(memberAttribute)에 의해 Person의 property는 암묵적으로 @DictionaryStorage가 붙게됨
- @attached(memberAttribute) 프로퍼티 위에 매번 선언하는 DictionaryRepresentable 생략 가능
@attached(member) 개념
- 기존에는 기존의 멤버에 새로운 특성을 추가했지만, @attached(member)는 완전히 새로운 멤버를 추가
- * 멤버: method, property, initializer
ex) @attached(member)매크로로 dictionary, init 추가
- 사용하는 쪽에서는 init과 dictionary 프로퍼티를 따로 선언해주지 않아도되는 간결한 코드가 탄생
@attached(conformance) 개념
- type이나 extension에 conformance (적합성)을 추가하는 매크로
ex) @attached(conformance)를 추가하여 Person 구조체에 일일이 DictionaryRepresentable을 준수하도록 해주지 않아도 됨
결과) DictionaryRepresentable을 선언해주지 않아도 됨 (@attached(conformance)에 의해서 자동으로 암시적으로 추가)
정리
- swift macro를 사용하면 코드를 중복 코드를 줄이면서 간결하게 표현이 가능
- @freestanding은 조합해서 사용 불가
- @attached는 조합해서 사용가능
before | after |
(간결해진 코드)
- 만약 DictinoaryStorage가 10개, 20개가 있고 macro를 안 쓴 경우 이 코드가 모두 중복될텐데 macro로 중복코드를 제거하고 간결하게 표현을 해주는 강력한 도구
(다음 포스팅 글에서 Macro 구현 방법, 올바른 Macro 작성 방법 계속)
* 참고
https://developer.apple.com/videos/play/wwdc2023/10167/