[SwiftUI] Property Wrapper (1)

DongHeon·2023년 10월 17일
0

SwiftUI

목록 보기
1/6
post-thumbnail

안녕하세요 오늘은 SwiftUI에서 사용되는 몇가지 Property Wrapper에 대해 알아보겠습니다.

그전에 먼저 Property Wrapper공식 문서를 통해 정리해 보겠습니다.

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

코드처럼 Property를 저장하는 방법을 관리하는 코드와 정의하는 코드 사이에 분리 계층을 추가합니다.

Wrapper를 사용하기 위해서는 Property 앞에 Wrapper를 추가합니다.

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

var rectangle = SmallRectangle()
print(rectangle.height)

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

rectangle.height = 24
print(rectangle.height) // 12보다 크기 때문에 12가 출력된다.

위 코드처럼 사각형의 높이를 24로 설정하게 되면 TweleveOrLess에서 허용하는 수인 12보다 큰 수이기 때문에 24대신 12를 저장하게 됩니다.

Property Wrapper도 initializer를 통해 값을 초기화 할 수 있습니다.

@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)
    }
}

이 중 3번째 init(wrappedValue:, maximum:)을 사용해 초기화하는 예시를 살펴보겠습니다.

struct NarrowRectangle {
    @SmallNumber(wrappedValue: 2, maximum: 5) var height: Int
    @SmallNumber(wrappedValue: 3, maximum: 4) var width: Int
}

var narrowRectangle = NarrowRectangle()
print(narrowRectangle.height, narrowRectangle.width)

narrowRectangle.height = 100
narrowRectangle.width = 100
print(narrowRectangle.height, narrowRectangle.width)

두 번째 출력 구문의 결과는 5, 4입니다. Property Wrapper를 초기화하는 과정에서 maximum을 각각 5,4로 초기화했기 때문입니다.

마지막으로 Projecting Value를 이용해 추가 기능을 노출할 수 있습니다.

이름에서처럼 Property Wrapper를 다른 값에 투영하는 것입니다.

@propertyWrapper
struct SmallNumber {
    private var number: Int
    private(set) var projectedValue: Bool


    var wrappedValue: Int {
        get { return number }
        set {
            if newValue > 12 {
                number = 12
                projectedValue = true
            } else {
                number = newValue
                projectedValue = false
            }
        }
    }


    init() {
        self.number = 0
        self.projectedValue = false
    }
}

struct SomeStructure {
    @SmallNumber var someNumber: Int
}
var someStructure = SomeStructure()

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

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

위 코드는 Projected Value를 이용해 초기화되는 값이 적합한지를 판단하고 있습니다.

이뿐만 아니라 다양한 방법으로 활용될 수 있는데 간단한 예시를 가져와 보겠습니다.

@propertyWrapper 
struct USDate {
    var wrappedValue: Date
    var projectedValue: String {
        let formatter = DateFormatter()
        formatter.dateFormat = "MM-dd-YYYY"
        return formatter.string(from: wrappedValue)
    }
}

struct Person {
    var name: String
    @USDate var birthDate: Date
}

let me = Person(name: "Stewart", birthDate: Date())
print(me.$birthDate) // "02-11-2023"

초기화한 Date 값을 Formatter를 통해 우리가 알아보기 쉬운 형태로 바꿀 수도 있습니다.

참고 자료

Linkedin

0개의 댓글