티스토리 뷰

Swift

[Swift] Property Wrapper 공식문서 번역

Kim_Baechu 2021. 9. 17. 14:01

https://docs.swift.org/swift-book/LanguageGuide/Properties.html

Property Wrappers

프로퍼티 래퍼는 프로퍼티를 어떻게 저장할지를 관리하는 코드와 프로퍼티를 정의하는 코드를 분리하는 레이어를 추가합니다.

스레드 세이프 체크나 데이터베이스에 기본 데이터를 저장하는 프로퍼티를 가지고 있다면, 모든 프로퍼티에 해당 코드를 적어야합니다.

프로퍼티 래퍼를 쓰면 프로퍼티 정의 코드를 한번 쓰고 적용할 여러 프로퍼티에 재사용하여 적용할 수 있습니다.

 

프로퍼티 래퍼를 정의하기 위해 구조체 열거형 클래스에 wrappedValue 프로퍼티를 만듭니다.

아래 코드는 12보다 작거나 같은 값을 저장하는 것을 보장하는 구조체입니다.12보다 큰 값을 저장하면 12를 대신 저장합니다.

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

setter는 12보다 작거나 같은 값을 저장하는걸 보장하고 getter는 저장된 값을 리턴합니다.

 

프로퍼티 앞에 attribute로 래퍼이름을 적어서 래퍼를 적용할 수 있습니다.

아래는 12보다 작거나 같은 값만 저장하는 직사각형 구조체입니다.

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

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

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

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

 

Setting Initial Values for Wrapped Properties

number에 초깃값을 줘서 wrapped property를 초기화할 수 있습니다.

이 프로퍼티 래퍼를 사용하는 코드는 다른 이니셜 값을 프로퍼티에 특정할 수 없습니다.

이니셜 값을 세팅하거나 커스터마이징하기 위해서, 프로퍼티래퍼는 추가 이니셜라이저가 필요합니다.

 

아래는 wrapped 값과 최댓값을 저장하는 이니셜라이저를 추가한 확장버전입니다.

@propertyWrapper
struct SmallNumber {
    private var maximum: Int
    private var number: Int

    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, maximum) }
    }

    init() {
        maximum = 12
        number = 0
    }
    init(wrappedValue: Int) {
        maximum = 12
        number = min(wrappedValue, maximum)
    }
    init(wrappedValue: Int, maximum: Int) {
        self.maximum = maximum
        number = min(wrappedValue, maximum)
    }
}

 

 

Projecting a Value From a Property Wrapper

propery wrapper는 projected value를 정의해서 추가 기능을 사용할 수 있습니다.

 

예를 들어, 데이터베이스에 대한 액세스를 관리하는 property wrapper는 flushDatabaseConnection()메서드를 projected value에 나타낼 수 있습니다.

projected value의 이름은 wrapped value와 똑같으며 $로 시작합니다.

당신의 코드가 $로 시작하는 프로퍼티를 정의할 수 없기 때문에 projected value는 당신이 지정한 프로퍼티에 간섭하지 않습니다.

 

아래 코드는 ProjectValue 프로퍼티를 SmallNumber 구조에 추가하여 property wrapper가 새 값을 저장하기 전에 프로퍼티의 새 값을 조정했는지 여부를 추적합니다.

 

@propertyWrapper
struct SmallNumber {
    private var number = 0
    private(set) var projectedValue = false
    var wrappedValue: Int {
        get { return number }
        set {
            if newValue > 12 {
                number = 12
                projectedValue = true
            } else {
                number = newValue
                projectedValue = false
            }
        }
    }
}
struct SomeStructure {
    @SmallNumber var someNumber: Int
}
var someStructure = SomeStructure()

someStructure.someNumber = 4
print(someStructure.$someNumber)
// Prints "false"

someStructure.someNumber = 55
print(someStructure.$someNumber)
// Prints "true"

someStructure.$someNumber를 이용해서 wrapper의 projected value에 접근할 수 있습니다.

4와 같이 작은 숫자를 저장하면 someStructure.$someNumber는 false가 됩니다.

하지만 55같이 큰 수를 저장하면 true가 됩니다.

 

property wrapper는 projected value의 어떤 타입의 값이든 리턴할 수 있습니다.

이번 예에서, property wrapper는 오직 하나의 정보만 보여주므로 Bool값은 projected value로 보여줍니다.

더 많은 정보를 표현해야하는 wrapper는 다른 데이터 타입들의 인스턴스를 리턴할 수 있습니다. 

또는 projected value로 wrapper의 인스턴스를 노출하기 위해 self를 리턴할 수 있습니다.

 

 

 

 

다음은 대문자로 시작하게 만들어주는 propertyWrapper입니다.

@propertyWrapper struct Capitalized {
    var wrappedValue: String {
        didSet { wrappedValue = wrappedValue.capitalized }
    }

    init(wrappedValue: String) {
        self.wrappedValue = wrappedValue.capitalized
    }
}

 

사용

struct User {
    @Capitalized var firstName: String
    @Capitalized var lastName: String
}

// John Appleseed
var user = User(firstName: "john", lastName: "appleseed")

// John Sundell
user.lastName = "sundell"

 

 

 

댓글
공지사항