Macro 에 대해서 알아보자. ( 수정중 )

2023. 11. 12. 00:53Mobile/Swift

 

State 를 공부하다가, Observable() 의 정의를 또 타고들어가다가 이것이 Macro 타입이라는 걸 알게되었다. 

 

Share observable state objects with subviews 부분에서

https://playground-coding.tistory.com/78

 

Macro 이게 무슨 역할을 하는 타입일까? Struct, Class, Instance Method, Properties, enum 등 이런 것들은 문법을 공부할 때 한번씩은 보던 것들인데, Macro 는 뭐지..

State 에 저장된 Observable 객체하위 뷰와 공유하려면 객체 참조를 하위 뷰에 전달

SwiftUI는 객체의 관찰 가능한 속성이 변경될 때마다 하위 뷰를 업데이트하지만 하위 뷰의 body가 속성을 읽을 때만 업데이트 한다.

예를 들어 BookView는 제목이 변경될 때마다 업데이트되지만, isAvailable 이 변경될 때에는 업데이트 되지 않는다.

참고로 Observable 은 현재 iOS 17.0+, Swift 5.9 문법에서 사용가능하다

 

Observable() 의 형태인 Macro 타입이 있고,

Observable 인 protocol 타입이 있다.

 

둘 다 Observation 이라는 프레임워크의 범주에 속하며, iOS 17.0 이상부터 사용가능하다.

기본 데이터가 변경되면 프레젠테이션을 업데이트 하는 반응형 앱을 만들 수 있다.

 

매크로를 사용하여 컴파일 타임 때 반복적인 코드를 생성할 수 있다고 한다.

Swift 매크로는 컴파일 타임에 소스 코드의 해당 부분을 생성해 Swift 에서 반복적인 코드 작성을 방지하는 데 도움이 된다고 한다. 매크로 호출은 항상 추가적이다. 매크로는 사용자가 작성한 코드와 함께 새 코드를 추가하지만 이미 프로젝트의 일부인 코드를 수정하거나 삭제하지는 않는다.

Swift 표준 라이브러리 및 다양한 프레임워크를 포함한 라이브러리가 매크로를 제공한다. 자신만의 매크로를 작성할 수도 있다. 매크로는 Swift 코드를 생성하므로 코드에서 매크로를 사용하는지 여부에 관계없이 개발 및 디버깅에 동일한 도구를 사용한다.

 

Call a Macro - 매크로 호출

매크로를 호출하는데 사용하는 구문은 매크로를 선언에 연결하는지 여부에 따라 약간 다르다. 선언에 매크로를 첨부하려면 매크로 앞에 @ 기호를 쓰고 이름 뒤에 매크로 인수를 쓴다. 이 구문은 속성을 작성하는 것과 동일하다.

선언에 첨부된 매크로는 코드를 생성하고 해당 코드를 선언에 추가한다. 예를 들어 Observable() 매크로는 MyObject 클래스에 추가 멤버를 추가하여 Observable 프로토콜을 구현하고 MyObject 를 Observable 을 준수하는 것으로 표시한다.

선언에 첨부하지 않고 매크로를 호출하려면 매크로 이름 앞에 # 기호를 사용하고 이름 뒤에 매크로 인수를 쓴다.

이 구문은 #if 및 컴파일 타임 작업과 동일하다 예를 들어,

let messagePredicate = #Predicate<Message> { message in
	message.recipient == "John Appleseed"
}

선언에 첨부되지 않은 매크로는 코드를 생성하고 매크로를 호출하는 위치에 해당 코드를 추가한다. 예를 들어 위코드의 Predicate 매크로는 Predicate 구조의 인스턴스를 생성한다.

매크로의 종류

Freestanding Macros

독립형 매크로는 #function 처럼 값을 생성할 수도 있고, #warning 처럼 컴파일 타임에 작업을 수행할 수도 있다.

import Foundation

func myFunction(name: String) -> String {
	
	 print("Currently running \\(#function)")
	 #warning("Something's wrong")
	return name
}

print(myFunction(name: "Seohyun"))

// Currently running myFunction(name:)
// Seohyun
// Program ended with exit code: 0

첫번째 줄에서 #function 은 Swift 표준 라이브러리에서 function() 매크로를 호출한다. 이 코드를 컴파일하면 Swift는 #function 현재 함수의 이름으로 대체하는 해당 매크로의 구현을 호출한다.

이 코드를 실행하고 myFunction() 을 호출하면 현재 실행중인 myFunction() 이 인쇄된다.

#warning 은 Swift 표준 라이브러리에서 warning(_:) 매크로를 호출해 사용자 정의 컴파일 시간 경고를 생성한다.

Attached Macros

첨부된 매크로를 호출하려면 이름 앞에 기호 @ 를 쓰고 이름 뒤에 괄호 안에 매크로에 대한 인수를 쓴다.

Attached Macros 는 자신이 첨부된 선언을 수정한다. 새로운 메소드를 정의하거나 프로토콜에 적합성을 추가하는 등 해당 선언에 코드를 추가한다.

struct SundaeToppings: OptionSet {
    let rawValue: Int
    static let nuts = SundaeToppings(rawValue: 1 << 0)
    static let cherry = SundaeToppings(rawValue: 1 << 1)
    static let fudge = SundaeToppings(rawValue: 1 << 2)
}

SundaeToppings 옵션 세트의 각 옵션에는 반복적이고 수동적인 초기화 호출이 포함되어 있다.

새 옵션을 추가할 때 줄 끝에 잘못된 숫자를 입력하는 등의 실수를 저지르기 쉽다.

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/macros/