티스토리 뷰

Mobile/iOS

iOS - Swift. Property Wrappers

out of coding 2023. 2. 6. 16:00

나온지 한참되었지만 다시 한번 정리하는 마음으로 적어봅니다.

처음에는 이것 접했을때 그러한 생각이 들었네요.

많이 보던건데?

 

백엔드에서 잘 사용하는 스프링 프레임워크에서 사용하는 어노테이션이랑 같은 부분이죠.

무언가를 주입하여 주기 위해서 사용하는!

그런데 프로퍼티 래퍼도 같은 의미라고 보면 됩니다.

 

A란변수에 이걸 적용해 달라고 하는것과 같습니다.

 

다음과 같이 사용 할 수 있습니다.

@propertyWrapper
struct TestPropertyWrapper {
    private var height = 0.0
    
    var wrappedValue: Double {
        get { height }
        set { height = (newValue - 100) * 0.7 }
    }
}

struct TestStruct {
    @TestPropertyWrapper
    var size: Double
}

func test() {
    var test = TestStruct()
    test.size = 178.9
    print(test.size.rounded())
}

test()
// 출력 : 55.0

다음과 같이 해서 UserDefault에 응용 가능합니다.

@propertyWrapper
struct UserDefault<T> {
    enum Key: String {
        case age = "age"
    }
    
    private let key: String
    private let defaultValue: T

    init(key: Key, defaultValue: T) {
        self.key = key.rawValue
        self.defaultValue = defaultValue
    }

    var wrappedValue: T {
        get {
            UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
        }
        set {
            UserDefaults.standard.set(newValue, forKey: key)
        }
    }
}

struct TestStruct {    
    @UserDefault(key: .age, defaultValue: 123)
    var age: Int
}

func test() {
    var test = TestStruct()
    test.age = 1
    print(test.age)
}

test()
// 출력 : 1

UserDefaults를 쉽게 접근할수 있도록 만들어줍니다. 좋네요.

 

wrappedValue에 대해서 알아봤으니 projectedValue에 대해서 알아볼게요.

혹시나 SwiftUI를 사용할 경우에 @State를 이용해서 선언했을 경우에 $를 붙여서 Binding으로 넘겨주는 형태를 사용해본적이 있나요?

Binding과 State는 한번 다시 정리해볼게요.

 

그런게 있다고 치면

wrappedValue는 그 값 자체를 의미하고요.

projectedValue는 내부에서 가지고 있는 다른 값을 의미합니다.

 

@State var name = "DDD"

이런 경우에

name으로 접근하면 바로 String의 형태입니다.

$name으로 접근하면? 바로 Binding 형태가 됩니다.

 

이것은 name으로 접근

이것은 Binding으로 접근됨

내부에서 무언가를 했다는 느낌이 들죠?

 

그래서 위에 만들었던 TestPropertyWrapper를 다음과 같이 수정해봤어요.

@propertyWrapper
struct TestPropertyWrapper {
    private var height = 0.0
    
    var wrappedValue: Double {
        get { height }
        set { height = (newValue - 100) * 0.7 }
    }
    
    var projectedValue: String {
        String("Hi: \(height)")
    }
}

struct TestStruct {
    @TestPropertyWrapper
    var size: Double
}

func test() {
    var test = TestStruct()
    test.size = 177.9
    print(type(of: test.$size))
    print(test.$size)
}

test()
// String
// Hi: 54.53

결과가 왜 이렇게 나온지 이해가 되었나요?

type은 string이고 formatting 된 string이 전달되었기 때문입니다.

 

궁금한점은 질문주세요

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함