안녕하세요. KataRN입니다.
오늘은 Property Wrapper에 대해 알아보겠습니다.
솔직히 너무 어렵네요 ㅠㅠ
최대한 풀어서 써보겠습니다...
우선 Property Wrapper의 정의는?
- 어떤 값이 있으면 이 값을 한 번 감싸서 저장을 위한 로직과 얻어오기 위한 로직을 어느정도 분리해서 반복을 줄여줄 수 있는 방법을 제공하는 속성입니다.
하.. 어렵다 어려워...
다른분들의 글과 똑같지만 다르게...(창의성이 부족하여... 참고하여...)... 예를 들어보겠습니다.
이마트에서 아이스크림을 팝니다.
행사를 해서 천원 이상은 무조건 천원이라고 하네요.
그럼 500원은? 500원이겠죠?
1500은? 1000원!
이걸 코드로 표현하면 아래와 같습니다.
struct Emart {
// 1. 최대 금액을 설정
private var maxPrice: Int = 1000
// 2. 접근제어자를 Private으로 설정하여 직접 접근 방지
private var _icecreamPrice: Int
// 3. setter를 이용하여 값 저장시 maxPrice를 넘을 수 없게 함.
var icecreamPrice: Int {
get { return _icecreamPrice }
set { _icecreamPrice = min(newValue, maxPrice)}
}
}
그런데 이벤트가 확장되어 과자, 물, 쌀, 껌도 하겠답니다...
이걸 적용하면 아래와 같습니다.
struct Emart {
private var maxPrice: Int = 1000
private var _icecreamPrice: Int
private var _snackPrice: Int
private var _waterPrice: Int
private var _ricePrice: Int
private var _gumPrice: Int
var icecreamPirce: Int {
get { return _icecreamPrice }
set { _icecreamPrice = min(newValue, maxPrice }
}
var snackPrice: Int {
get { return _snackPrice }
set { _snackPrice = min(newValue, maxPrice }
}
var waterPrice: Int {
get { return _waterPrice }
set { _waterPrice = min(newValue, maxPrice }
}
var ricePrice: Int {
get { return _ricePrice }
set { _ricePrice = min(newValue, maxPrice }
}
var gumPrice: Int {
get { return _gumPrice }
set { _gumPrice = min(newValue, maxPrice }
}
}
이거 뭔가 비효율적이네하고 생각해볼만한건 역시 enum으로 묶어서 처리하기?
struct Emart {
enum Product {
case icecream
case snack
case water
case rice
case gum
}
private var maxPrice: Int = 1000
private var icecreamPirce: Int
private var snackPirce: Int
private var waterPirce: Int
private var ricePirce: Int
private var gumPirce: Int
func getPrice(_ prudct: Product) -> Int {
switch product {
case .icecream: return icecreamPirce
case .snack: return snackPirce
case .water: return waterPirce
case .rice: return ricePirce
case .gum: return gumPirce
}
}
mutating func setPrice(food: Food, price: Int) {
let realPrice = min(price, maxPrice)
switch food {
case .icecream: self.icecreamPrice = realPrice
case .snack: self.snackPrice = realPrice
case .water: self.waterPrice = realPrice
case .rice: self.ricePrice = realPrice
case .gum: self.gumPrice = realPrice
}
}
이제 Property Wrapper을 사용해봅시다.
@propertyWrapper
struct MaxPriceOrLessWrapper {
private var max = 1000
private var value = 0
var wrappedValue: Int {
get { return value }
set { value = min(newValue,max) }
}
}
struct Emart {
@MaxPriceOrLessWrapper var icecreamPrice: Int
@MaxPriceOrLessWrapper var snackPrice: Int
@MaxPriceOrLessWrapper var waterPrice: Int
@MaxPriceOrLessWrapper var ricePrice: Int
@MaxPriceOrLessWrapper var gumPrice: Int
}
📢 사용법
struct를 만들고 그 위에(혹은 앞에) @propertyWrapper를 붙여준다.
그러면 wrappedValue라는것을 선언해줘야하는데, 이 Property Wrapper가 붙은 모든 값은 wrappedValue 연산프로퍼티로 값을 뱉고 정의한다. (안써주면 오류납니다.)
상당히 간결해졌네요.
여기에 초기값을 무조건 0으로 해야되는가?
@propertyWrapper
struct MaxPriceOrLessWrapper {
private var max: Int
private var value: Int
init(value: Int, maxPrice: Int) {
self.max = maxPrice
self.value = min(value, maxPrice)
}
var wrappedValue: Int {
get { return value }
set { value = min(newValue,max) }
}
}
struct Emart {
@MaxPriceOrLessWrapper(value: 9000, maxPrice: 10000)
var icecreamPrice: Int
@MaxPriceOrLessWrapper(value: 12000, maxPrice: 10000)
var snackPrice: Int
@MaxPriceOrLessWrapper(value: 7500, maxPrice: 10000)
var waterPrice: Int
@MaxPriceOrLessWrapper(value: 400, maxPrice: 500)
var ricePrice: Int
@MaxPriceOrLessWrapper(value: 1000, maxPrice: 500)
var gumPrice: Int
}
이처럼 중복도 없고~ 너무 좋네요~
UserDefaults 예제가 꼭 나오는데 확인한번 해보도록하죠.
class UserManager {
static var usesTouchID: Bool {
get { return UserDefaults.standard.bool(forKey: "usesTouchID") }
set { UserDefaults.standard.set(newValue, forKey: "usesTouchID") }
}
static var myEmail: String? {
get { return UserDefaults.standard.string(forKey: "myEmail") }
set { UserDefaults.standard.set(newValue, forKey: "myEmail") }
}
static var isLoggedIn: Bool {
get { return UserDefaults.standard.bool(forKey: "isLoggedIn") }
set { UserDefaults.standard.set(newValue, forKey: "isLoggedIn") }
}
}
이것을 Property Wrapper를 이용해서 바꿔보도록하죠.
@propertyWrapper
struct UserDefault<T> {
let key: String
let defaultValue: T
var wrappedValue: T {
get { UserDefaults.standard.object(forKey: self.key) as? T ?? self.defaultValue }
set { UserDefaults.standard.set(newValue, forKey: self.key) }
}
}
class UserManager {
@UserDefault(key: "usesTouchID", defaultValue: false)
static var usesTouchID: Bool
@UserDefault(key: "myEmail", defaultValue: nil)
static var myEmail: String?
@UserDefault(key: "isLoggedIn", defaultValue: false)
static var isLoggedIn: Bool
}
Property Wrapper가 반복될 수 있는 구문을 간편하고 알아보기 쉽게 만들기에 좋네요.
그리고 UserDefaults에 가장 잘 활용할 수 있다고하니까 활용해보는것도 좋을것 같습니다.
저는 솔직히 오늘 이후로 UserDefault는 propertyWrapper을 사용할 것 같습니다.
다만 좀 어려웠던 내용이었던지라 제 생각은 별로 담지 못한점 죄송합니다.
더 노력하겠습니다.
오늘도 긴글 읽어주셔서 감사합니다.
- 참고 : https://dongminyoon.tistory.com/52, https://zeddios.tistory.com/1221, https://jiseobkim.github.io/swift/2021/06/13/swift-Property-Wrapper.html
'Old_SWIFT(221012) > 기본이야기' 카테고리의 다른 글
Result 타입에 대하여... (0) | 2022.10.05 |
---|---|
Error타입부터 try, do, catch까지...(모든건 Result 타입을 위해) (1) | 2022.10.05 |
함수의 종류(인스턴스 메서드, 타입 메서드, instance method, type method) (1) | 2022.10.04 |
Mutating에 대하여... (0) | 2022.10.03 |
멀티 스레딩을 위한 API(Operation Queue, NSOperation Queue) (0) | 2022.09.30 |