-
Property WrapperSwift 2022. 3. 25. 23:55
안녕하세요.
요즘 SwiftUI에 대해서 학습을 하고 있는 와중에 @State니 @Binding이니 낯선 키워드들을 접하게 되었습니다.
그러고 보니 Combine을 사용하면서 @Published와 같은 Property Wrapper들을 사용하고 있었는데요.
오늘은 그 Property Wrapper에 대해서 알아보도록 하겠습니다.
1. Property Wrapper
https://docs.swift.org/swift-book/LanguageGuide/Properties.html#ID617
Property Wrapper를 한국말로 생각해보면 속성 포장지(?)라는 뜻을 가지고 있는데요.
저는 특정 프로퍼티에 특징을 부여한다!라는 뜻으로 이해했습니다.
@State의 경우에는 읽고 쓸 수 있는 프로퍼티라고 선언하는 것이고
@Published 같은 경우는 값을 방출할 수 있는 프로퍼티라고 말하는 것이죠.
만약 여러 프로퍼티들에서 같은 getter/setter가 반복해서 사용되는 경우
해당 코드를 Property Wrapper를 통해 정의해주게 되면 재사용성이 올라가고 프로퍼티를 정의하는 부분의 가독성이 좋아집니다.
그럼 Property Wrapper를 직접 정의하는 방법은 매우 간답합니다.
바로 @propertyWrapper 어노테이션을 구조체, 클래스, 열거형 앞에 붙여주면 됩니다.
그렇게 타입을 생성하면 wrappedValue, 즉 포장된 값을 포함하지 않다고 합니다.
TwelveOrLess 타입은 저장하려는 값과 12 중에 더 작은 값을 가지는 타입입니다.
따라서 다음과 같이 정의할 수 있겠죠.
@propertyWrapper struct TwelveOrLess { private var number: Int = 0 var wrappedValue: Int { get { return number } set { number = min(newValue, 12) } } }
이렇게 정의한 Property Wrapper는 다른 타입의 프로퍼티 앞에 @TwelveOrLess를 붙여서 사용할 수 있습니다.
struct Rectangle { @TwelveOrLess var height: Int @TwelveOrLess var width: Int }
하지만 이렇게만 정의하면 문제가 조금 있습니다.
바로 생성자의 변수의 Int 타입이 아니라 Property Wrapper타입인 것입니다.
이러한 문제는 Property Wrapper에 init(wrappedValue: Int)를 추가하므로 해결할 수 있습니다.
@propertyWrapper struct TwelveOrLess { private var number: Int = 0 var wrappedValue: Int { get { return number } set { number = min(newValue, 12) } } init(wrappedValue: Int) { self.wrappedValue = wrappedValue } }
위와 같이 wrappedValue를 매개변수로 하는 생성자는 프로퍼티에 값이 할당된 경우 호출됩니다.
따라서 위와 같이 구조체에서 height와 width에 초기값을 주었을 때도 init(wrappedValue:)가 호출되는 것이죠.
따라서 초기값을 부여하지 않고 생성할 때도 의도한 대로 Int형을 이용해 인스턴스를 생성할 수 있습니다.
또한 Property Wrapper는 추가적인 기능을 제공할 수 있는 projectedValue라는 프로퍼티를 추가할 수 있습니다.
공식문서에서는 값의 변화 여부를 판단하는 데 사용하였습니다.
@propertyWrapper struct TwelveOrLess { private var number: Int = 0 private(set) var projectedValue: Bool = false var wrappedValue: Int { get { return number } set { if newValue > 12 { number = 12 projectedValue = true } else { number = newValue projectedValue = false } } } init(wrappedValue: Int) { self.wrappedValue = wrappedValue } }
위와 같이 Bool 타입의 projectedValue를 선언하고 12보다 값이 커서 값이 변경된 경우에는 projectedValue를 true로 설정했습니다.
projectedValue는 외부에서 해당 프로퍼티의 앞에 $를 붙여서 사용할 수 있습니다.
꼭 Bool 타입이 아니라 다른 타입으로도 선언이 가능하니 상황에 맞게 사용하면 될 것 같습니다.
'Swift' 카테고리의 다른 글
Model-View-Presenter(MVP) (0) 2022.04.04 Model-View-Controller(MVC) (0) 2022.04.03 SOLID 원칙 (0) 2022.01.28 Codable (0) 2021.12.28 NSCoder (0) 2021.12.27