본문 바로가기

코딩의 유익함/스위프트(Swift)

Swift(스위프트) - Property Wrappers(프로퍼티 래퍼) 알아보기

Swift - Property Wrappers

Swift 문법을 공부하다 보면, 또는 누군가가 작성해놓은 프로그램을 보다 보면 프로퍼티 앞에 @가 붙은 어떤 선언 속성을 접하신 적 있으시지요? 바로 그 @가 붙은 Property Wrappers에 대해서 알아보도록 하겠습니다.

 

보통 Property Wrappers 쉽게 코드를 재사용하거나, 반복되는 코드를 제거하기 위해 많이 사용합니다.

 

그림) Property Wrappers(1)

위 그림처럼 커스텀 Property Wrappers를 만들려면 @Property Wrappers 붙여주면 되는데요. 아래의 예제를 작성하면, 결과적으로 @StandardWeight를 프로퍼티 앞에 붙여 사용할 수 있게 됩니다.

 

자, 그런데 익숙하지 않은 wrappedValue 변수가 하나 있는데요. 이 변수는 커스텀 Property Wrappers를 구현할 때 필수로 작성해야 하는 변수로, 실질적으로 핵심적인 역할을 하는 변수입니다.

 

이제 이 wrappedValue 변수에 getter, setter 메서드를 구현해주시면 되는데요, 그 안의 기능은 여러분이 원하시는 기능을 넣으시면 됩니다. 위 그림에서는 표준 몸무게를 계산하는 기능을 넣었습니다.

 

결과적으로 나의 키를 입력하게 되면, 표준 몸무게가 자동으로 계산이 되게끔 만들어질 텐데요. 그럼 이제 만든 커스텀 Property Wrappers를 적용해 보겠습니다.

 

그림) Property Wrappers(2)

위 그림은 @StandardWeight 속성의 tall 프로퍼티를 가지는 Person 타입의 구조체를 선언하였습니다. 여기서 주의할 점은 이 속성의 선언은 지역, 전역 변수에는 적용할 수 없다는 점입니다. 

 

자, 그럼 Person 구조체의 인스턴스를 하나 생성 후 키(tall)의 값을 입력하겠습니다. 그런데 이 프로퍼티는 @StandardWeight의 속성을 가지고 있기 때문에 wrappedValue의 set 메서드가 작동하게 됩니다.

 

그러면 newValue에 186.9의 값이 들어가고, (186.9 - 100) * 0.9를 weight 프로퍼티에 저장하게 됩니다. 마지막으로 이 키(tall) 프로퍼티의 값을 출력하게 되면 wrappedValue의 get 메서드가 작동합니다.

 

결과적으로 set 메서드가 작동하고 저장되어 있던 weight 변수가 출력되게 되는 것이죠. 위의 rounded()는 소수점 이하를 다 자르는 역할을 하는 함수입니다. 여기까지 잘 이해가 되셨나요?

 

그런데, 한 가지 문제가 있습니다. 성별에 따라서 표준 무게가 다르다는 것인데요. 그렇다면 이번에는 성별의 값을 초기 값으로 전달하여 성별에 따라 다른 값이 출력되도록 해보겠습니다.

 

그림) Property Wrappers(3)

그림) Property Wrappers(1)와 비교해 달라진 점은 열거형 Sex를 추가한 것과, set 메서드가 성별에 따라 다른 값을 저장하도록 바뀌었네요.(남녀 표준 몸무게 공식도 변경) 또 생성자고 추가되었고요.

 

위와 같이 설정했을 경우 아래와 같이 선언과 동시에 초기 값으로 지정하여 활용할 수 있습니다.

그림) Property Wrappers(4)

Person 구조체의 man_tall 프로퍼티는 186.9로 값을 설정하고 있기 때문에 생성자로 sex만을 인자로 전달하면 되고, woman_tall은 값을 할당하지 않아 wrappedValue까지 같이 전달하고 있습니다.

 

여기서 유의할 점은, 생성자로 인자를 전달할 때 wrappedValue를 포함해야 한다면, 반드시 첫 번째 인자로 전달해야 한다는 것입니다. 그렇지 않으면 에러가 발생하게 되겠지요.

 

자, 추가로 Property Wrappers를 적용했을 때 컴파일러는 어떻게 동작하는 것일까요? 그 원리를 한번 살펴보겠습니다. 컴파일러는 Property Wrappers를 사용하면 자동으로 코드를 생성합니다.

 

예를 들어 @StandardWeight(sex: StandardWeight.Sex.man) var man_tall: Double = 186.9 이렇게 작성을 했다면, 실제로는 아래와 같이 코드를 생성하여 실행하게 됩니다.

 

private var _man_tall: StandardWeight = StandardWeight(wrappedValue:186.9, StandardWeight.Sex.man)
var man_tall: Double {
get { return _man_tall.wrappedValue }
nonmutating set { _man_tall.wrappedValue = newValue }

그런데 위의 경우에 Property Wrappers 타입의 변수(_man_tall)에는 외부에서 접근이 불가합니다. private로 선언이 되어있기 때문이죠. 이를 해결하기 위해 다른 방법을 제공하고 있습니다.

 

바로, Property Wrappers를 작성할 때 body에 다음과 같이 projectedValue 프로퍼티를 추가해주면 되는데요. 위 예제로 예를 들면, 아래와 같이 추가해주면 됩니다.

 

그림) Property Wrappers(5)

위와 같이 추가가 되었다면, 프로퍼티에 $가 붙은 변수를 사용할 수 있는데요. 다음과 같은 코드로 출력이 가능합니다. 

그림) Property Wrappers(6)

정신없이 공부하면서 작성한 내용이기에 조금 두서가 없을 수도 있음을 양해 부탁드립니다.

 

감사합니다.