4T2F / ThinkBig

๐ŸŒŸ์”ฝํฌ๋น… ์Šคํ„ฐ๋””๐ŸŒŸ
5 stars 1 forks source link

Userdefaults์™€ Appstorage์˜ ์ฐจ์ด #56

Open Hsungjin opened 5 months ago

Hsungjin commented 5 months ago

Intro

App๋‚ด์—์„œ ํŠน์ • ๊ฐ’๋“ค์„ ์•ฑ์ด ๊บผ์ง„์ƒํƒœ์—์„œ๋„ ์ €์žฅํ•˜๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ๋ ๊นŒ์š”?

Userdefaults์™€ @AppStorage๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ €์žฅํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Userdefaults๋Š” ๊ธฐ์กด UIkit์—์„œ ๋งŽ์ด ์‚ฌ์šฉํ–ˆ๋˜ ๋ฐฉ์‹์ด๊ณ  AppStorage๋Š” SwiftUI์—์„œ iOS 14๋ถ€ํ„ฐ ์ƒˆ๋กœ์ƒ๊ธด ๋‚ด์šฉ ์ž…๋‹ˆ๋‹ค.

์ด๋ฒˆ์—๋Š” ๋‘๊ฐœ์˜ ๊ฐœ๋…์— ๋Œ€ํ•ด ์„ค๋ช…ํ•˜๊ณ  ๋‘๊ฐœ์˜ ์ฐจ์ด์— ๋Œ€ํ•ด ์•Œ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


What is UserDefaults

Apple์—์„œ๋Š” "App์„ ์‹คํ–‰ํ•˜๋Š” ๋™์•ˆ ์ง€์†์ ์œผ๋กœ key-value๋กœ ์ €์žฅํ•˜๋Š” ์‚ฌ์šฉ์ž์˜ ๊ธฐ๋ณธ Database์— ๋Œ€ํ•œ Interface"๋ผ๊ณ  ํ•ด์š”.

์‰ฝ๊ฒŒ ๋งํ•ด ๋ณ„๋„์˜ DB ์—†์ด App์— ๋‚ด๊ฐ€ ์›ํ•˜๋Š” ๊ฐ’์„ ์–ด๋–ค Key์™€ ํ•จ๊ป˜ ์ €์žฅํ•˜๊ณ , ์–ธ์ œ๋“  ๊ทธ Key๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ๋ถˆ๋Ÿฌ๋‚ผ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด์ฃ .ย 

๋‹จ, 512KB ์ดํ•˜์˜ ๊ฐ„๋‹จํ•œ String, Bool, Int, Array ๋“ฑ ๋‹จ์ผ Data๋ฅผ ์ €์žฅํ•˜๋Š” ๋ฐ์— ์ ํ•ฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋Œ€๋Ÿ‰์˜ Data๋ฅผ ์ €์žฅํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ๋”ฐ๋กœ Database๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•ฉ๋‹ˆ๋‹ค!

๊ฐ„๋‹จ ์นด์šดํ„ฐ ์˜ˆ์‹œ

๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ฒ„ํŠผ์„ ํ†ตํ•ด ์นด์šดํ„ฐ๋ฅผ ์ฆ๊ฐ€ํ•˜๋Š” ์•ฑ์ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณผ๊ฒŒ์š”

struct ContentView: View {
    @State private var count: Int = 0

    var body: some View {
        VStack {
            Text("clicked count: \(count)")
            Button("click") {
                count += 1
            }
        }
    }
}


์œ„์˜ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ํด๋ฆญ ํšŸ์ˆ˜๊ฐ€ ํ™”๋ฉด์— ํ‘œ์‹œ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทผ๋ฐ ์œ„ ์ฝ”๋“œ์ƒ์—์„œ๋Š” ์•ฑ์„ ์ข…๋ฃŒํ•ฌ๋‹ค๊ฐ€ ๋‹ค์‹œ ํ‚ค๋ฉด ์นด์šดํŠธ๊ฐ€ 0์ด ๋˜์–ด๋ฒ„๋ฆฌ๊ฒ ์ฃ ?

๊ทธ๊ฒƒ์„ UserDefaults๋ฅผ ์ด์šฉํ•ด์„œ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

struct ContentView: View {
    @State private var count = UserDefaults.standard.integer(forKey: "Clicked")

    var body: some View {
        VStack {
            Text("์ด ์นด์šดํŠธ : \(count)")
            Button("์นด์šดํŠธ ์ฆ๊ฐ€") {
                count += 1
                UserDefaults.standard.set(count, forKey: "Clicked")
            }
        }
    }
}

๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜๋ฉด ์•ฑ์„ ์ข…๋ฃŒํ–ˆ๋‹ค๊ฐ€ ๋‹ค์‹œ ์‹คํ–‰์„ ์‹œ์ผœ๋„ count๋ผ๋Š” ๋ณ€์ˆ˜๊ฐ€ UserDefaults์˜ ํ‚ค ๊ฐ’์„ ํ†ตํ•ด ๊ฐ’์„ ๋ฐ›์•„์˜ค๊ธฐ ๋•Œ๋ฌธ์— ์ €์žฅ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๋ ค๋ฉด?

๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” UserDefaults.standerd.set(๊ฐ’, forkey: "ํ‚ค๊ฐ’") ์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

UserDefault.standard.set(0, forkey: "number")    //Integer ํƒ€์ž… ๋ฐ์ดํ„ฐ ์ €์žฅ
UserDefault.standard.set(false, forkey: "boolean")    //Boolean ํƒ€์ž… ๋ฐ์ดํ„ฐ ์ €์žฅ
UserDefault.standard.set("Hi", forkey: "string")    //String ํƒ€์ž… ๋ฐ์ดํ„ฐ ์ €์žฅ


๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋ ค๋ฉด?

๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ ์œ„ํ•ด์„œ๋Š” UserDefaults.standerd.์ž๋ฃŒํ˜•(key: "ํ‚ค๊ฐ’") ์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

let string = UserDefault.standard.string(key: "string") ?? ""
let number = UserDefault.standard.integer(key: "number")
let boolean = UserDefault.standard.bool(key: "boolean")

๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ๋•Œ ์ฒ˜์Œ ๊ฐ’์ด ์ €์žฅ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด Int์™€ Float, Double ํƒ€์ž…์€ 0์„, Bool ํƒ€์ž…์€ false๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

String ํƒ€์ž…์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ๋•Œ ์ฃผ์˜ํ•  ์ ์€ ์ฒ˜์Œ ๊ฐ’์ด ์ €์žฅ๋˜์–ด ์žˆ์ง€ ์•Š์œผ๋ฉด nil์„ ๋ฐ˜ํ™˜ํ•˜๊ธฐ ๋•Œ๋ฌธ์— optional binding์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•œ๋‹ค.


๋ฐ์ดํ„ฐ๋ฅผ ์‚ญ์ œ ํ•˜๋ ค๋ฉด?

๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” UserDefaults ์ธ์Šคํ„ด์Šค์˜ removeObject ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉ ์‚ญ์ œํ•œ๋‹ค.

UserDefault.standard.removeObject(forKey:"numebr")


UserDefaults๋ฅผ ์ข€๋” ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ• ์ˆ˜ ์—†์„๊นŒ?

์ €๋Š” UserDefaults๋ฅผ ์ข€๋” ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด์„œ Extension์„ ํ†ตํ•ด ๊ด€๋ฆฌ ํ•ฉ๋‹ˆ๋‹ค.

๋ฏธ๋ฆฌ set, get์— ๋Œ€ํ•ด ์ •์˜๋ฅผ ํ•ด๋†“๊ณ  ๋ฐ”๋กœ ํ˜ธ์ถœํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋งŒ๋“ค์–ด ๋†“์Šต๋‹ˆ๋‹ค.

extension UserDefaults {
    private static let isNoti = "notiKey"

    func setUserNoti(_ noti: String) {
        set(noti, forKey: UserDefaults.isNoti)
    }

    func getUserNoti() -> String? {
        return string(forKey: UserDefaults.isNoti)
    }
}

์œ„์˜ ์ฝ”๋“œ๋Š” ์ œ๊ฐ€ ์‹ค์žฌ๋กœ ์‚ฌ์šฉํ–ˆ๋˜ ์˜ˆ์‹œ ์ž…๋‹ˆ๋‹ค.

set๊ณผ get์— ๋Œ€ํ•ด์„œ ๋ฏธ๋ฆฌ ์ •์˜ ๋˜์–ด ์žˆ์ฃ ?

์ด๋ ‡๊ฒŒ ์ž์ฃผ ์‚ฌ์šฉ๋  ๊ฐ’๋“ค์„ ๋ฏธ๋ฆฌ ์ •์˜ํ•ด๋†“๊ณ  ์‚ฌ์šฉํ•˜๋ฉด ๊ฐ€๋…์„ฑ๋„ ์˜ฌ๋ผ๊ฐ€๊ณ  ์ข‹์€๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.


What is @AppStorage

Userdefaults์™€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์—ญํ• ์€ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์šฉ์„ฑ์—์„œ ํฌ๊ฒŒ ์ฐจ์ด๊ฐ€ ์žˆ๊ณ , ํ•˜์œ„๋ทฐ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋„˜๊ฒจ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„์˜ ํ”„๋กœ์ ํŠธ ์˜ˆ์‹œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉด

@State private var count = UserDefaults.standard.integer(forKey: "cliked")

๋ญ”๊ฐ€ ์ฝ”๋“œ๊ฐ€ ๊ธธ์–ด ๋ณด์ด์ง€ ์•Š๋‚˜์š”?

์ด๊ฒƒ์— ๋Œ€ํ•ด ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด iOS 14๋ฒ„์ „ ์ด์ƒ ๋ถ€ํ„ฐ @State ์†์„ฑ์„ ํฌํ•จํ•˜์—ฌ ๋ฐ์ดํ„ฐ ์ €์žฅ๊นŒ์ง€ ํ•œ๋ฒˆ์— ํ•  ์ˆ˜ ์žˆ๋Š” property wrapper ๊ฐ€ ๋‚˜์™”์Šต๋‹ˆ๋‹ค.

๊ทธ๊ฒŒ ๋ฐ”๋กœ @AppStorage ์ž…๋‹ˆ๋‹ค.

import SwiftUI

struct ContentView: View {
    @AppStorage("cliked") private var count = 0

    var body: some View {
        VStack {
            Text("clicked count: \(count)")
            Button("click") {
                count += 1
            }
        }
    }
}

๊ทธ๋ž˜์„œ ์–ด๋–ค์ƒํ™ฉ์— ์–ด๋–ค๊ฑธ ์‚ฌ์šฉํ• ๊นŒ?

UserDefaults์˜ ์ฃผ์š” ์‚ฌ์šฉ ์˜ˆ์‹œ

@AppStorage์˜ ์ฃผ์š” ์‚ฌ์šฉ ์˜ˆ์‹œ

๊ทธ๋ž˜์„œ ๊ฒฐ๋ก ์ ์œผ๋กœ๋Š”


UIKit์—์„  @AppStorage๋ฅผ ๋ชป์“ธ๊นŒ?

"๋„ค"

@AppStorage๋Š” SwiftUI์˜ ์ผ๋ถ€๋กœ์„œ ์„ค๊ณ„๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— UIKit์—์„œ๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. @AppStorage๋Š” SwiftUI์˜ ๋ทฐ ๋ชจ๋ธ๊ณผ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ์‹œ์Šคํ…œ์— ํ†ตํ•ฉ๋˜์–ด ์žˆ์–ด, SwiftUI ๋‚ด์—์„œ ๋ฐ์ดํ„ฐ์˜ ์ €์žฅ ๋ฐ ์—…๋ฐ์ดํŠธ๊ฐ€ ๋ทฐ์™€ ์ง์ ‘์ ์œผ๋กœ ์—ฐ๊ฒฐ๋  ์ˆ˜ ์žˆ๊ฒŒ ๋•์Šต๋‹ˆ๋‹ค.