Swift | Property Wrapper. 그리고 UserDefaults에서의 활용.

Swift 5.1 부터의 이야기

다들 iOS 개발에서 UserDefaults의 저장과 불러오기 어떻게 실행하고 있으신가요?

WWDC2019에서도 발표된 내용이지만 PropertyWrapper를 활용하면
늘 반복했던 10줄 남짓의 코드을 통일시키는게 가능해집니다. 💪

PropertyWrapper가 뭔지 알아보러 가시죠 고고싱 ~ !

1. Property Wrapper?

Property Wrapper 는 한국말로 하면 property 감싸기? 감싸개? 같은 느낌입니다.

연산 프로퍼티(Computed property)의 getter, setter를 기본으로 가진 구조체(Property)를 Property wrapper 라고 합니다.


1-1. 연산 프로퍼티(Computed property)의 getter, setter?

연산 프로퍼티의 활용예를 알아봅시다.

final class BankAccount {

    private var money: Double = 0

    var savedMoney: Double {
        get { money }
        set { money = newValue * 1.002 }
    }

}

위와 같은 경우, class 밖에서는 savedMoney를 통해서만 money를 참조할 수 있습니다.
이 때 savedMoney가 BankAccount 이외의 모든 class에서 필요하면 어떻게될까요?
똑같은 코드를 반복해서 작성해야 할까요.

각 class 또는 struct에서 반복되는 연산프로퍼티를 하나의 struct로 정의하는 것이 바로 Property wrapper 입니다.


1-2. Property wrapper

You can also use a property wrapper to reuse code in the getter and setter of multiple properties.
속성 래퍼를 사용하여 여러 속성의 getter 및 setter에서 코드를 재사용 할 수도 있습니다.


실제로 코드에서 어떻게 정의되는지 살펴보죠 !

@propertyWrapper
struct SavedMoney {
    private var money: Double = 0.0

    var wrappedValue: Double {
        get { money }
        set { money = newValue * 1.002 }
    }

    init(wrappedValue: Double) {
        self.wrappedValue = wrappedValue
    }
}

사실 정의는 기존 struct 의 정의 시작 전에 @propertyWrapper 를 추가해주는 것 이외의
다른 점이 없습니다.

사용할 때 코드가 struct 와 다릅니다

struct OriginBankAccount {
    @SavedMoney var money: Double
}

struct SalaryBankAccount {
    @SavedMoney var money: Double
}

print(OriginBankAccount(money: 1.0)) // 결과 : 1.002

type 자체는 원하는 변수와 같게 정의하지만
property 정의의 맨 앞에 @propertyWrapper명 을 정의해줍니다.

Property wrapper 를 활용하면 여러 class 혹은 struct 에서 반복적으로 해줘야하는 랩핑을 통일할 수가 있습니다 ! 아주 편리하쥬

일반적인 property들처럼 명명도 가능해서 알아보기도 쉽답니다. 😖


2. Property Wrapper의 활용

편리해보이는 Property wrapper, 어디에 활용해야 잘 활용했다고 소문이 날까요 !
WWDC에서의 애플의 예제대로 UserDefaults에서의 사용이 활용도가 가장 높을 것 같네요.

@propertyWrapper
struct UserInfo {
    private let key: String

    var wrappedValue: String {
        get { UserDefaults.standard.string(forKey: key) ?? "" }
        set { UserDefaults.standard.set(newValue, forKey: key) }
    }

    init(key: String) {
        self.key = key
    }
}

struct FamilyUser {
    @UserInfo(key: "user-id") var userID: String
    @UserInfo(key: "family-id") var familyID: String
}

// 사용
struct Users {
    let familyUser = FamilyUser()

    func printFamilyUserInfo() {
        print("유저 ID : \(familyUser.userID)")
        print("가족 ID : \(familyUser.familyID)")
    }
}

적당한 예제를 찾지 못한 것 같지만 UserInfo 처럼 정해진 패턴을 가지고 UserDefaults에 저장된 값이라면
Property wrapper를 활용해서 UserDefaults.standard.~ 로 반복되는 코드를 통일시키는게 훨씬 좋을 것 같네요 !

UserDefaults 이외에도 이미 반복적인 getter와 setter를 사용한 곳이라면 다양하게 활용이 가능하다고 생각해요.


알고나면 유용한 Property Wrapper !
적재적소한 장소에 활용이 되셨으면 좋겠어요 ~ 오늘도 즐거운 iOS 개발되세용 🧚‍♀️

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Google photo

Google의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 /  변경 )

%s에 연결하는 중