@dynamicMemberLookup 알아보기

마이노·2024년 1월 19일
0

일반적으로 사용하지는 않지만 라이브러리의 코드를 들여다 보면 @dynamicMemberLookup 라고 적힌 Attribute를 심심치 않게 볼 수 있습니다.

그렇다면 어떠한 용도로 사용되고 있는지 살펴보고자 합니다.

https://docs.swift.org/ 를 확인해보면 다음과 같이 설명하고 있습니다.

class, struct, enum 또는 protocol에 이 특성을 적용하면 런타임에 멤버를 이름으로 조회할 수 있습니다.

런타임에 멤버를 조회한다는 것은 어떠한 의미일까요?

직접 만들어보며 알아가봅시다.

저는 다음과 같은 구조체에 프로퍼티를 하나 만들었습니다.

이상태에서 dynamicMemberLookup을 붙여서 사용해봅시다!

당연히 바로 붙인다고 사용되지는 않습니다.

ExpressibleByStringLiteral 프로토콜을 채택하거나, keyPath를 사용하라고 알려주는 문구입니다.

멤버를 이름으로 조회하기 위해선 어떻게 조회하는지 나타내주어야 합니다.

따라서 에러를 해결하기위해 subscript를 만들어야 합니다.

이 subscript는 singer를 입력받아 koreaSinger의 있는 key값에 해당하는 value를 반환하는 동작을 하고 있습니다. 일치하는 값이 없을 수도 있기 때문에 optional String으로 리턴값을 잡아주었습니다.

준비는 끝입니다!

이제 객체를 하나 만들어 subscript 내용대로 해당하는 키값을 dot syntax를 통해 접근할 수 있습니다.

예상한 것처럼 singer에 dot syntax를 사용해서 접근을 할 수 있습니다.

이제 다시 위의 내용에서 해결 못한 런타임 시점에 대해 확인해보려고 합니다.

dot syntax를 사용해서 접근해보면 어디에서도 키값을 찾아볼 수 없습니다.

이유는 컴파일 타임에 유형을 확인할 수 없기 때문입니다. 따라서 런타임 시점에 값을 접근할 수 있게 만들어 코드를 작성할 때에는 어떠한 에러나 오류로 인식하지 않습니다.

dynamicMemberLookup의 네이밍이 좀 더 이해가 가실것이라고 생각합니다.

동적으로 어떠한 타입의 멤버를 조회하는것 → 런타임 시점에 동적으로 호출되어 조회

dynamicMemberLookup을 dot syntax로 나타낼 때 컴파일 타임에 알게하고싶다면 어떻게 접근해야할까요?

이를 래핑하는 유형을 생성하는 것으로 해결할 수 있습니다.

다음과 같은 간단한 구조체를 하나 만들어줍니다.

아까는 subscript에 String type의 singer를 매개변수로 받았던 것을 기억하실겁니다.

dynamicMemberLookup의 매개변수에는 2가지가 들어올 수 있습니다.

하나는 ExpressibleByStringLiteral 입니다.

이것은 무엇일까요? 문자열 리터럴로 표현이 가능한 형식의 프로토콜입니다

String은 해당 프로토콜을 채택하고 있기 때문에 dot syntax로 singer를 곧바로 때려넣어도 작동되는 것이였습니다. 이외에 해당 프로토콜을 채택하고 있는 여러가지 타입들이 존재하니 찾아보셔도 좋을 것 같습니다!

두번째는 KeyPath입니다.

KeyPath는 기본적으로 immutable입니다. 즉 Wrapper 구조체가 let 프로퍼티를 가지고 있을 때 사용하는 읽기전용 KeyPath입니다.

이러한 KeyPath는 여러가지 종류가 존재합니다. WritableKeyPath과 ReferenceWritableKeyPath도 존재하는데 두개의 차이점은 무엇일까요? 네이밍만 보아도 참조가 붙은것으로 보아 참조타입에서 사용가능한 KeyPath라고 생각하셨다면 정답입니다! 이와 반대로 붙지 않았다면 값타입에서 사용되는 KeyPath입니다.

이제 다시 subscript로 돌아와서 자세히 살펴보겠습니다.

Value라는 제네릭 타입을 하나 만들어주었습니다. 내부 프로퍼티 value는 Value타입과 동일합니다.

member에서 KeyPath는 <Value, T>입니다. 리턴값은 T이구용

즉 Value 타입에서 T라는 값을 유추해 T를 리턴받는 동작을 하고 있습니다.

그 결과 wrapper는 CatCafe의 내부 프로퍼티에 곧바로 접근할 수 있습니다.

첫번째로 ExpressibleByStringLiteral프로토콜을 채택한
subscript의 매개변수와

두번째의 KeyPath를 매개변수로 넣었을 때 총 두가지의 방식으로 dynamicMemberLookup을 구성해보았습니다.

지금까지 dynamicMemberLookup을 알아보았습니다.
앞으로 라이브러리를 깔 때 만나게 된다면 더이상 두려워하지 않아도 될것같아요..!

profile
아요쓰 정벅하기🐥

0개의 댓글