Jiseob Kim

iOS Developer

Swift - Property Wrapper(๊ธฐ๋ณธ)

13 Jun 2021 » Swift


๊ทธ ๋™์•ˆ 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
}

์•„์ฃผ ์•„์ฃผ ์•„์ฃผ ์‹ฌํ”Œํ•ด์กŒ๋‹ค. ๊น”๋”! ๋ช‡์ค„์ด ์ค„์€๊ฑฐ์ง€?


๊ทธ๋Ÿผ ์‹ค์ œ๋กœ ์ž˜ ๋™์ž‘ํ•˜๋Š”์ง€๋„ ํ™•์ธํ•ด๋ณด์ž

์•„์ฃผ ์•„์ฃผ ํ›Œ๋ฅญํ•˜๋‹ค.

ํ•˜์ง€๋งŒ ๋ณด๋Š”๊ฒƒ๊ณผ ๊ฐ™์ด ์•„์‰ฌ์šด์ ์€ ์กฐ๊ธˆ ์žˆ๋‹ค.

  1. ์œ„์™€ ๊ฐ™์ด ์ดˆ๊ธฐ๊ฐ’์ด 0์ด๋ผ๋Š” ์ ?
  2. 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์— ๋Œ€ํ•ด์„œ๋งŒ ๋ณด์ž

ํ•„์š”ํ•œ ๊ฒƒ

  1. Key - ๋น ์งˆ ์ˆ˜ ์—†์ง€
  2. 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์— ๊ด€ํ•œ๊ฒƒ์ด๋‹ค.


๋.