๊ทธ ๋์ Property Wrapper
์ ๋ํ ๊ธ์ ์ข
์ข
๋ณด์์ง๋ง,
์ ํํ ์ด๋ป๊ฒ ์ด๋์ ์จ์ผ๊ฒ ๋จ ์๊ฐ์ด ํ์คํ๊ฒ ๋ค์ง ์์์๋ค.
๊ทธ๋๋ง ๋ง์ ๊ธ์์ ๋ค๋ฃจ์๋๊ฑด UserDefault
์ ์ฐ์ด๋ ๊ฒ์ ์กฐ๊ธ ํฅ๋ฏธ๋ก์ ๋ค.
ํ์ง๋ง ๊ณ์ ๋ฏธ๋ฃจ๊ณ ๋ฏธ๋ฃจ๊ณ ๋ฏธ๋ฃจ๊ณ ๋ฏธ๋ฃจ๋ค๊ฐ ์ด์ ์์ผ ํฅ๋ฏธ๊ฐ ๊ฐ๋งํ ์ฌ์ฉ์ฒ๊ฐ ๋ฐ๊ฒฌ ๋์๋ค.
์ต๊ทผ ๊ธ์ ์ฃผ์ ์๋ Codable
๊ณผ CodingKey
๊ณผ ๊ด๋ จ์ด ์๋ ๋ถ๋ถ์ด๋ผ ๋ง์์ ๋จน๊ฒ ๋๋ค.
์ด๋ฒ ์ฃผ์ ๋ Property Wrapper
๊ฐ๋
๋ถํฐ ์ก๊ณ ๊ฐ๊ธฐ.
์ตํ๊ฐ๋ฉด์ ๋๋ ์๊ฐ์
ํ๋กํผํฐ๋ฅผ ์ด๊ธฐํ ํ ๋, ์ฐ์ฐ ํ๋กํผํฐ(getter/setter) ๊ฐ๋ ์ ์ถ๊ฐ ์ ์ฉํ๋ ๊ฒ (100% ๊ฐ์ธ ์๊ฐ)
ํ์ค๋ก ๋งํ๊ธฐ ์ ๋ง ์ด๋ ต๋ค. ๋ช๋ฒ์ ์ง์ด์ง ๋ชจ๋ฅด๊ฒ ๋ค.
์ฌ์ฉํ๋ ๊ณณ์ด ์๊ฐ๋ณด๋ค ๋ค์ํ๊ฒ ์ด๋ฃจ์ด์ ธ์ ๊ทธ๋ ๋ค.
๊ทธ๋์ ํฌ์คํ ์ ๋ช์ฐจ๋ก ๋๋ ์ง๊ฒ์ด๊ณ ,
๋ค์ํ๊ฒ ์๊ฐ๋ฅผ ํด๋ณผ๊นํ๋ค.
Property Wrapper ์ฌ์ฉ์
๊ฐ์ : ํธ๋ํธ๋ญ Struct๊ฐ ์๊ณ , ์ฌ๊ธฐ์ ํ๋งค ๋๋ ์์๋ค์ 10,000์ ์ดํ๋ผ๋ ํน์ง์ด ์๋ค.
์ฒซ์งธ๋ก ํผ์๋ง ํ๋งคํ๋ค๊ณ ๊ฐ์ ํด๋ณด์.
struct FoodTruck {
var pizzaPrice: Int
}
10,000์ ์ดํ๋ผ๋ ํน์ง์ด ์๋ค๋ฉด ์์ ๊ฐ์ด ๋จ์ํ๊ฒ ๊ฐ์ ๋ฃ๊ณ ๋นผ๊ณ ํ๊ฒ ๋ ๊ฒ์ด๋ค.
๊ทธ๋ ์ง๋ง ๊ทธ ํน์ง์ด ๋ค์ด๊ฐ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ด ๋ฐ๋์ด์ผ ํ ๊ฒ์ด๋ค.
struct FoodTruck {
// 1. ์ต๋ ๊ธ์ก ์ค์
private var maxPrice: Int = 10000
// 2. ์ ๊ทผ ์ ์ด์๋ฅผ Private์ผ๋ก ํด์ค์ผ๋ก์จ ์ง์ ์ ๊ทผ ๋ฐฉ์ง
private var _pizzaPrice: Int
// 3. setter๋ฅผ ์ด์ฉํ์ฌ ๊ฐ ์ ์ฅ์ maxPrice์ ๋์ ์ ์๊ฒ ํจ.
var pizzaPrice: Int {
get { return _pizzaPrice }
set { _pizzaPrice = min(newValue, maxPrice)}
}
}
์ ์ฌ๊ธฐ๊น์ง๋ ๋ญ ๊ทธ๋ฅ์ ๋ฅ ์ด๋ ๊ฒํ๋ฉด ๋๋๊ฑฐ์๋๊ฐ ์ถ๋ค.
๋ง๋ค.
๊ทผ๋ฐ, ์ฌ๋ฌ๊ฐ๋ฅผ ํ๋ค๊ณ ๊ฐ์ ํด๋ณด์. ํผ์, ํ์คํ, ์นํจ, ์ํ, ๊น์น ์ ๋
struct FoodTruck {
private var maxPrice: Int = 10000
private var _pizzaPrice: Int
private var _pastaPrice: Int
private var _chickenPrice: Int
private var _soupPrice: Int
private var _kimchiPrice: Int
var pizzaPrice: Int {
get { return _pizzaPrice }
set { _pizzaPrice = min(newValue, maxPrice)}
}
var pastaPrice: Int {
get { return _pastaPrice }
set { _pastaPrice = min(newValue, maxPrice)}
}
var chickenPrice: Int {
get { return _chickenPrice }
set { _chickenPrice = min(newValue, maxPrice)}
}
var soupPrice: Int {
get { return _soupPrice }
set { _soupPrice = min(newValue, maxPrice)}
}
var kimchiPrice: Int {
get { return _kimchiPrice }
set { _kimchiPrice = min(newValue, maxPrice)}
}
}
์ค ๊ต์ฅํ ๊ธธ์ด์ง๋ค.
๋ค๋ฅธ ๋ฐฉ๋ฒ์ ๋ญ๊ฐ ์์๊น, ์ง๊ธ ๋ ์ค๋ฅด๋ ์ ๋๋ enum์ ์ด์ฉํ๊ธฐ?
struct FoodTruck {
enum Food {
case pizza
case pasta
case chicken
case soup
case kimchi
}
private var maxPrice: Int = 10000
private var pizzaPrice: Int
private var pastaPrice: Int
private var chickenPrice: Int
private var soupPrice: Int
private var kimchiPrice: Int
func getPrice(_ food: Food) -> Int {
switch food {
case .pizza: return pizzaPrice
case .pasta: return pastaPrice
case .chicken: return chickenPrice
case .soup: return soupPrice
case .kimchi: return kimchiPrice
}
}
mutating func setPrice(food: Food, price: Int) {
let realPrice = min(price, maxPrice)
switch food {
case .pizza: self.pizzaPrice = realPrice
case .pasta: self.pastaPrice = realPrice
case .chicken: self.chickenPrice = realPrice
case .soup: self.soupPrice = realPrice
case .kimchi: self.kimchiPrice = realPrice
}
}
}
ํ , ๋ญ๊ฐ ๊ทธ๋๋ ์ฝ๋ ๊ฐ๊ธด ํ์ง๋ง ๊ธธ์ด์ง๋ฏํ๊ณ ,
Property Wrapper
๋ฅผ ๋ณด๊ณ ๋๋ enum
๋ ๋๋ฌด ์๋ฆฌ ์ฐจ์ง ๋ง์ดํ๋ฉฐ
๊ทธ์ ๋ฐ๋ผ switch
๋ฌธ๋ ๋๋ฌด ๊ธธ๊ฒ ๋๊ปด์ง๋ค.
์ฌ์ง์ด get/set
2๊ฐ๋ค!
์ฒ์์ ๋๋์ ์ ๋งํ๊ฒ ์ฒ๋ผ,
ํ๋กํผํฐ ์ด๊ธฐํ์ ,getter์ setter์ ๊ฐ๋ ์ ์ถ๊ฐํด์ค๋ค๋ผ๋ ๊ฒ์ ์ ๋ณด์ฌ ์ค ์ ์์ ๊ฒ ๊ฐ๋ค.
Property Wrapper ์ฌ์ฉํ
์ฌ์ฉ ์ค๋น
๋จ์ ์ด๋ผ๊ณ ํ๋ฉด ์๋ก์ด ๋ชจ๋ธ์ ๋ง๋ค์ด์ค์ผ ํ๋ค๋์ ? ๊ทธ์ธ์๋ ์ ๋ชจ๋ฅด๊ฒ ๋ค.
์ผ๋จ, ๊ธ์ก ์ ํ์ ๊ฑธ๋ฆฐ ๊ฐ์ฒด๋ฅผ ํ๋ ๊ตฌ์ฑํด๋ณด์
@propertyWrapper
struct MaxPriceOrLessWrapper {
private var max = 10000
private var value = 0
var wrappedValue: Int {
get { return value }
set { value = min(newValue,max) }
}
}
struct
๋ฅผ ๋ง๋ค๊ณ ๊ทธ ์์(ํน์ ์์) @propertyWrapper
๋ฅผ ๋ถ์ฌ์ค๋ค.
๊ทธ๋ฌ๋ฉด wrappedValue
๋ผ๋๊ฒ์ ์ ์ธํด์ค์ผํ๋๋ฐ,
์ด Property Wrapper
๊ฐ ๋ถ์ ๋ชจ๋ ๊ฐ์
wrappedValue
์ฐ์ฐํ๋กํผํฐ๋ก ๊ฐ์ ๋ฑ๊ณ ์ ์ํ๋ค.
์ด๊ฒ ํต์ฌ์ด๋ค. ์์จ์ฃผ๋ฉด ์ค๋ฅ๋จ!
๋ด์ฉ์ ์์ฃผ ๊ฐ๋จํ๋ค. ์ต๋ ๊ธ์ก์ ์ ์ด์ฃผ์๊ณ , ์ฐ์ฐ ํ๋กํผํฐ ํ๋๋ฅผ ์ ์ด์ฃผ์๋ค.
๊ทธ๋ผ ์ด๊ฒ์ ์ด๋ป๊ฒ ์ ์ฉํ๋๊ฐ?
์ฌ์ฉํ๊ธฐ
struct FoodTruck {
@MaxPriceOrLessWrapper var pizzaPrice: Int
@MaxPriceOrLessWrapper var pastaPrice: Int
@MaxPriceOrLessWrapper var chickenPrice: Int
@MaxPriceOrLessWrapper var soupPrice: Int
@MaxPriceOrLessWrapper var kimchiPrice: Int
}
์์ฃผ ์์ฃผ ์์ฃผ ์ฌํํด์ก๋ค. ๊น๋! ๋ช์ค์ด ์ค์๊ฑฐ์ง?
๊ทธ๋ผ ์ค์ ๋ก ์ ๋์ํ๋์ง๋ ํ์ธํด๋ณด์
์์ฃผ ์์ฃผ ํ๋ฅญํ๋ค.
ํ์ง๋ง ๋ณด๋๊ฒ๊ณผ ๊ฐ์ด ์์ฌ์ด์ ์ ์กฐ๊ธ ์๋ค.
- ์์ ๊ฐ์ด ์ด๊ธฐ๊ฐ์ด 0์ด๋ผ๋ ์ ?
- MaxPrice๊ฐ ๋ค ๋ค๋ฅผ์๋ ์์์? (๋์ ํธ, ๋ฉ์ธ ์์ ๋ณ๋ก?)
๊ทธ ์์ฌ์๋ ๋ฌ๋ ์ ์๋ค.
๋ค์๊ณผ ๊ฐ์ด property wrapper
๋ฅผ ๋ฐ๊พธ์ด์ค๋ค
@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) }
}
}
์ด๊ธฐ ์ธํ ์ ์ปค์คํ ํ๊ฒ ๋ค! ๋ผ๋ ๊ฒ์ด๊ณ
value
๋ ๋ง์ฐฌ๊ฐ์ง๋ก maxPrice
๋ฅผ ๋์ง ์๋๋ค.
์ด๋ป๊ฒ ์ฐ๋๊ฐ?
์ด๋ ๊ฒ ์ด๋ค.
struct FoodTruck {
@MaxPriceOrLessWrapper(value: 9000, maxPrice: 10000)
var pizzaPrice: Int
@MaxPriceOrLessWrapper(value: 12000, maxPrice: 10000)
var pastaPrice: Int
@MaxPriceOrLessWrapper(value: 7500, maxPrice: 10000)
var chickenPrice: Int
@MaxPriceOrLessWrapper(value: 400, maxPrice: 500)
var soupPrice: Int
@MaxPriceOrLessWrapper(value: 1000, maxPrice: 500)
var kimchiPrice: Int
}
๋๋ฐ.. ๊ฐ๋จํด..
๊ทธ๋ฆฌ๊ณ ์ด์ ์ฝ๋๋ฅผ ๊ฐ ๋ณ๊ฒฝ์์ด ์ฒ์ print๋ง ๋ณด์
๋๋ฌด ์ข๋ค.
UserDefault์ ์ ์ฉํด๋ณด๊ธฐ
WWDC ์ธ์
์๋ ๋ฑ์ฅํ๋ค๋ UserDefault
์ Property Wrapper
์ฐ๊ธฐ!
๊ธฐ๋ณธ์ ์ผ๋ก UserDefault
๋ผ ํจ์ key
๋ฅผ ๊ฐ์ง๊ณ ๊ฐ์ ์ ๊ทผํ์ฌ
์ฐ๊ฑฐ๋ ์ป์ด ์ค๊ฑฐ๋ ํ๋ค. ๋ค๋ฅธ๋ง๋ก setter ํ๊ฑฐ๋ getter ํ๋ค.
์ด ๋ํ ์ฒ์์ ๋งํ๊ฒ์ฒ๋ผ Property Wrapper
๋ ๋ญ๋ค?
ํ๋กํผํฐ๋ฅผ ์ด๊ธฐํ ํ ๋, ์ฐ์ฐ ํ๋กํผํฐ(getter/setter) ๊ฐ๋ ์ ์ถ๊ฐ ์ ์ฉํ๋ ๊ฒ (100% ๊ฐ์ธ ์๊ฐ)
๊ทธ๋ผ ๋ Property Wrapper
๊ฐ ์๊ธฐ ์ ๊ณผ ํ๋ฅผ ๋น๊ตํด๋ณด์
UserDefault์ ์ ์ฉํด๋ณด๊ธฐ - ์ฌ์ฉ ์
struct UserDefaultManager {
private static var ud = UserDefaults.standard
static var userName: String {
get {
return ud.value(forKey: "userName") as? String ?? ""
}
set {
ud.setValue(newValue, forKey: "userName")
}
}
static var hasMembership: Bool {
get {
return ud.value(forKey: "hasMembership") as? Bool ?? false
}
set {
ud.setValue(newValue, forKey: "hasMembership")
}
}
}
๋จ 2๊ฐ๋ฅผ ์ผ์ ๋ฟ์ธ๋ฐ ๊ดํธ์ ์ด๊ฒ ์ ๊ฒ ๋๋ฌด ๋ง๋ค.
์ค์ ๋ก๋ ์ ๋ ๊ฒ ์ฐ์ธ ์ฝ๋ ๋ง์ง๋ชปํด ์ผ์ง๋ง ์ ๋ง ๊ฑฐ์ฌ๋ ธ๋ค.
๋ฐ๋ณต์ ๋ฐ๋ณต์ด ๋๋ฌด ๋ง๋ค.
UserDefault์ ์ ์ฉํด๋ณด๊ธฐ - ์ฌ์ฉ ํ
์ฐจ๊ทผ์ฐจ๊ทผ ๊ฐ์ ํด๋ณด์
์ฐ์ String
์ ๋ํด์๋ง ๋ณด์
ํ์ํ ๊ฒ
Key
- ๋น ์ง ์ ์์งdefaultValue
- ์์๋ ์ป์ ๊ธฐ๋ณธ๊ฐ ์ ๋๋ ์์ผ๋ฉด ์ข๊ฒ ๋ค.
@propertyWrapper
struct UserDefaultWrapper {
private let ud = UserDefaults.standard
// 1. ํค
private let key: String
// 2. ๊ธฐ๋ณธ ๊ฐ
private var defaultValue: String
// 3. wrappedValue ์ ์
var wrappedValue: String {
get {
return ud.value(forKey: key) as? String ?? defaultValue
}
set {
ud.setValue(newValue, forKey: key)
}
}
// 4. ์ด๊ธฐ๊ฐ ๋ฐ ํค ์
ํ
init(key: String, defaultValue: String) {
self.key = key
self.defaultValue = defaultValue
}
}
์ด์ ์ด ์ฝ๋๋ ์ด๋ ต์ง ์์ ๊ฒ์ด๋ค
๊ทธ๋ผ ํ๋ฒ ์ ์ฉํด๋ณด์.
struct UserDefaultManager {
private static var ud = UserDefaults.standard
// Property Wrapper ์ ์ฉ
@UserDefaultWrapper(key: "userName", defaultValue: "")
static var userName: String
static var hasMembership: Bool {
get {
return ud.value(forKey: "hasMembership") as? Bool ?? false
}
set {
ud.setValue(newValue, forKey: "hasMembership")
}
}
}
userName
๊ณผ hasMembership
์ค์ userName
์๋ง ์ ์ฉ์ ํด๋ณด์๋ค.
๋๋ฌด ์ฌํํ๋ค. ๊ดํธ์ ๋ฐ๋ณต์ ์ง์ฅ์์ ๋ฒ์ด๋ ๋๋ ใ
๊ทผ๋ฐ, ๊ฑฑ์ ์ด ๋ ์ ์๋ค. String
๋ง ํ์ผ๋๊น ๋ค๋ฅธ ํ์
๋ค๋ ๋ค ์ ์๋ฅผ ํด์ผํด? ๋ผ๋ ๊ฑฑ์ .
๊ทธ์น๋ง ์ฐ๋ฆฌ์๊ฒ Generics
์ด ์๋ค.
์ ์ฉํด๋ณด์
@propertyWrapper
struct UserDefaultWrapper<T> { // 1. ์ฌ๊ธฐ์ ์ ๋ค๋ฆญ ์จ์ฃผ๊ณ
private let ud = UserDefaults.standard
private let key: String
// 2. ์ฌ๊ธฐ๋ ์ ๋ค๋ฆญ ์จ์ฃผ๊ณ
private var defaultValue: T
// 3. ์ฌ๊ธฐ๋ ์ ๋ค๋ฆญ ์จ์ฃผ๊ณ
var wrappedValue: T {
get {
// 4. ์ฌ๊ธฐ๋ ์ ๋ค๋ฆญ ์จ์ฃผ๊ณ
return ud.value(forKey: key) as? T ?? defaultValue
}
set {
ud.setValue(newValue, forKey: key)
}
}
// 5. ์ฌ๊ธฐ๋ ์ ๋ค๋ฆญ ์จ์ฃผ๊ณ
init(key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
}
์ด 5๊ตฐ๋ฐ์ ์ ๋ค๋ฆญ์ ์ ์ฉํด์ฃผ์๋ค.
์ด๊ฑด ์ด์ ํ์ ๋ถ๋ฌธํ๊ณ ๋ค ์จ์ค ์ ์๋ค.
ํด๋ณด์.
struct UserDefaultManager {
@UserDefaultWrapper(key: "userName", defaultValue: "")
static var userName: String
@UserDefaultWrapper(key: "hasMembership", defaultValue: false)
static var hasMembership: Bool
}
์์ฐ ๋ฏธ์ณค๋ค.
๋ค์ ํ๋ฒ ์ ์ฉ ์ ์ ์ฝ๋๋ฅผ ๋ณด์
// Property Wrapper ์ ์ฉ ์ ์ฝ๋
struct UserDefaultManager {
private static var ud = UserDefaults.standard
static var userName: String {
get {
return ud.value(forKey: "userName") as? String ?? ""
}
set {
ud.setValue(newValue, forKey: "userName")
}
}
static var hasMembership: Bool {
get {
return ud.value(forKey: "hasMembership") as? Bool ?? false
}
set {
ud.setValue(newValue, forKey: "hasMembership")
}
}
}
์ฐจ์ด๋ ์ด๋ง๋ฌด์ํ๋ค.
์ฌ์ฉ์ ์ฌ์ฉ ์ ํ๊ฐ ๋ค๋ฅผ๊ฒ ์์ง๋ง ๊ทธ๋๋ ์ฐ๋๊ฑด ๋ค์๊ณผ ๊ฐ์ด.
๋ง๋ฌด๋ฆฌ
๊ณต๋ถ๋ฅผ ํ๋ฉฐ ์ฝ๋ ์์ฑํ๋ฉด์๋ ๋๋ฌ๋๋ฐ, ๋ธ๋ก๊ทธ ๊ธ ์ฐ๋ฉด์ ๋ณด๋ ๋ ๋๋ผ์ ๋ค.
๊ต์ฅํ ๊ฐ๊ฒฐํด์ง๋ค๋ ์ ์ด ์ธ์์ ์ด๋ค.
์ ์ด์ ๊ณต๋ถํ์ง?
์ฝ๋๋ฅผ ๋ณด๋ฉด init
์ด ๊ต์ฅํ ์ค์ํ๋ค.
์์ด๋ ์ธ ์๋ ์์ง๋ง init
์ด ๋ค์ด๊ฐ๋ฉด ๋ ํ์ฉ์ฑ์ด ์ข๋ค๋๊ฒ.
์ฌ๊ธฐ์ ์ฐ์ธ init
๋ ์์ง๋ง, ์ด์ ํฌ์คํ
์ค์ Codable
์ ์ด์ฉํ init
์ด ์กด์ฌํ๋ค.
init(from decoder: Decoder) throws {}
์ฌ๊ธฐ์๋ ์ ์ฉ์ ํ ์๊ฐ ์์๋ค.
์ ๋ง ์ด๊ฑฐ ์ ์ฉํด๋ณด๊ณ ์๋ฆฌ ์ง๋ ๋ค.
๊ทธ๋์ ๋ค์ ์ฃผ์ ๋ Codable
๊ณผ Property Wrapper
์ ๊ดํ๊ฒ์ด๋ค.
๋.