Properties - The Swift Programming Language (Swift 5.7)

Property Wrappers

Property wrapper는 프로퍼티가 저장되는 방법을 관리하는 코드와 프로퍼티를 정의하는 코드 사이의 분리 계층을 추가한다.

예) Thread-safety 검사를 제공하거나 기본 데이터를 데이터베이스에 저장하는 프로퍼티가 있는 경우, 모든 프로퍼티에 해당 코드를 작성해야 한다. 프로퍼티 래퍼를 사용할 때, 래퍼를 정의할 때 관리 코드를 한 번 작성한 다음, 여러 프로퍼티에 적용하여 관리 코드를 재사용한다.

프로퍼티 래퍼를 정의하려면 wrapValue 프로퍼티를 정의하는 구조체, 열거형 또는 클래스를 만든다. 아래 코드에서, TwelveOrLess 구조는 그것이 감싸는 값이 항상 12보다 작거나 같은 숫자를 포함하도록 보장하는 것이다. 더 큰 숫자를 저장해 달라고 요청하면, 12개를 대신 저장한다.

@propertyWrapper
struct TwelveOroLess {
		private var number = 0
		var wrappedValue: Int {
				get { return number }
				set { number = min(newValue, 12) }
		}
}

NOTE

위의 예에서 숫자에 대한 선언은 변수를 비공개로 표시하며, 이는 숫자가 TwelveOrLess의 구현에만 사용된다는 것을 보장한다. 다른 곳에서 작성된 코드는 wrappedValue의 getter와 setter를 사용하여 값에 접근하며, 숫자를 직접 사용할 수 없다. 비공개에 대한 정보는 접근제어를 참고하라

프로퍼티 앞에 래퍼의 이름을 프로퍼티로 작성하여 프로퍼티에 래퍼를 적용한다. 다음은 TwelveOrLess 프로퍼티 래퍼를 사용하여 치수가 항상 12이하인지 확인하는 직사각형을 저장하는 구조이다.

struct SmallRectangle {
		@TwelveOrLess var height: Int
		@TwelveOrLess var width: Int
}

var rectangle = SmallRectangle()
print(rectangle.height)
// print "0"

rectangle.height = 10
print(rectangle.height)
// print "10"

rectangle.height = 24
print(rectangle.height)
// print "12"

높이와 너비 프로퍼티는 TwelveOrLess.number를 0으로 설정하는 TwelveOrLess의 정의에서 초기 값을 가져온다. TwelveOrLess의 sette는 10을 유효한 값으로 취급하므로 rectangle.height에 숫자 10을 저장하면 쓰여진 대로 진행된다. 그러나, 24는 TwelveOrLess가 허용하는 것보다 크므로, 24를 저장하려고 하면rectangle.height를 12로 대신 설정하게 된다.

프로퍼티에 래퍼를 적용할 때, 컴파일러는 래퍼에 대한 저장소를 제공하는 코드와 래퍼를 통해 프로퍼티에 대한 접근을 제공하는 코드를 합성한다. (프로퍼티 래퍼는 래핑된 값을 저장할 책임이 있으므로 합성된 코드가 없다.)

특별한 프로퍼티 구문을 활용하지 않고도 프로퍼티 래퍼의 동작을 사용하는 코드를 작성할 수 있다. 예를 들어, @TwelveOrLess를 프로퍼티로 작성하는 대신 TwelveOrLess 구조로 프로퍼티를 명시적으로 감싸는 이전 코드 목록의 SmallRectangle 버전이 있다.

struct SmallRectangle {
    private var _height = TwelveOrLess()
    private var _width = TwelveOrLess()
    var height: Int {
        get { return _height.wrappedValue }
        set { _height.wrappedValue = newValue }
    }
    var width: Int {
        get { return _width.wrappedValue }
        set { _width.wrappedValue = newValue }
    }
}