본문 바로가기
SwiftUI 독학으로 기본기 익히기

07. UserDefaults로 데이터를 저장하는 세 가지 방법

by daco2020 2025. 11. 1.

지난 시간 우리가 만든 투두리스트 앱은 데이터를 따로 저장하지는 않기 때문에 앱을 다시 실행하면 기존의 데이터가 지워집니다.

 

이번 글에서는 UserDefaults를 이용해서 데이터를 영속적으로 저장하는 세 가지 방법에 대해 알아보겠습니다.

 


 

 

UserDefaults로 데이터를 저장하는 세 가지 방법

UserDefaults의 핵심은 "Key-Value" 쌍으로 데이터를 저장하는 것입니다. 예를 들어, "username"이라는 이름표(Key)에 "eunchan"이라는 값(Value)을 저장하는 것과 같습니다.

 

(Key : Value)
"username" : "eunchan"

 

 

방법 1. 기본 데이터 직접 읽고 쓰기

가장 단순하고 직접적인 방법입니다. String, Int, Bool, Double 등 기본 데이터 타입을 저장할 때 사용합니다.

 

언제 사용하나요? 앱의 간단한 설정(예: 알림 허용 여부, 다크 모드 설정)이나 단일 정보(예: 사용자 이름)를 저장할 때 적합합니다.

 

 

예시 코드

// UserDefaults에 접근하는 표준 방법
let defaults = UserDefaults.standard

// --- 데이터 저장하기 (Write) ---
let username = "Gemini"
let launchCount = 5
let isDarkMode = true

defaults.set(username, forKey: "savedUsername")
defaults.set(launchCount, forKey: "appLaunchCount")
defaults.set(isDarkMode, forKey: "darkModeEnabled")

// --- 데이터 읽어오기 (Read) ---
// string(forKey:)는 값이 없을 수 있으므로 String? (Optional) 타입으로 반환됩니다.
let savedUsername = defaults.string(forKey: "savedUsername") ?? "Guest" // 값이 없으면 "Guest"를 기본값으로

// integer(forKey:)는 값이 없으면 0을 반환합니다.
let savedLaunchCount = defaults.integer(forKey: "appLaunchCount")

// bool(forKey:)는 값이 없으면 false를 반환합니다.
let darkModeIsEnabled = defaults.bool(forKey: "darkModeEnabled")

print("\(savedUsername)님, \(savedLaunchCount + 1)번째 방문입니다. 다크모드: \(darkModeIsEnabled)")

// --- 데이터 삭제하기 (Delete) ---
defaults.removeObject(forKey: "savedUsername")

 

 

특징

- 명령형: "이 값을 이 키로 저장해라", "저 키에 있는 값을 가져와라" 처럼 직접 명령해야 합니다.

- 뷰 연동: SwiftUI 뷰와 연동할 때 onAppear와 같은 수동 코드가 필요합니다.

 

 


 

 

 

방법 2: Codable 객체 변환하여 읽고 쓰기

struct나 class로 만든 우리만의 커스텀 데이터 타입(배열 포함)을 저장하는 방법입니다. JSONEncoder와 JSONDecoder를 사용합니다.

 

언제 사용하나요? 복잡한 데이터 구조를 통째로 저장하거나 불러올 때 사용하거나, Swift 데이터를 JSON 같은 외부 데이터 형식으로 바꾸어 보낼 때 주로 사용합니다.

 

 

예시 코드

struct UserProfile: Codable {
    let name: String
    let level: Int
}

let defaults = UserDefaults.standard
let encoder = JSONEncoder()
let decoder = JSONDecoder()

// --- 데이터 저장하기 (Write) ---
let userProfile = UserProfile(name: "Gemini", level: 99)

// 1. 객체를 Data 타입으로 인코딩
if let encodedData = try? encoder.encode(userProfile) {
    // 2. 인코딩된 Data를 UserDefaults에 저장
    defaults.set(encodedData, forKey: "userProfileData")
}

// --- 데이터 읽어오기 (Read) ---
// 1. UserDefaults에서 Data를 가져옴
if let savedData = defaults.data(forKey: "userProfileData") {
    // 2. 가져온 Data를 다시 우리 객체로 디코딩
    if let decodedProfile = try? decoder.decode(UserProfile.self, from: savedData) {
        print("프로필 로드 성공: \(decodedProfile.name), 레벨 \(decodedProfile.level)")
    }
}

 

특징

- 변환 과정 필요: 객체를 직접 저장할 수 없으므로, JSONEncoder를 통해 인코딩(변환)하는 과정이 필요합니다.

- 통째로 관리: 데이터를 개별적으로 저장하는 것이 아니라 객체나 배열 전체를 하나의 데이터 덩어리로 취급합니다.

 

 


 

 

 

방법 3: @AppStorage 사용하기

SwiftUI는 UserDefaults와 @State를 합친 것 같은 아주 편리한 기능을 제공합니다. 바로 @AppStorage입니다.

 

언제 사용하나요? SwiftUI 뷰 안에서 UserDefaults의 값이 바뀔 때 화면을 자동으로 업데이트하고 싶을 때 사용합니다.

 

 

예시 코드

import SwiftUI

struct SettingsView: View {
    // "@AppStorage"가 UserDefaults와 뷰를 연결해 줍니다.
    // "darkModeEnabled"라는 Key를 사용하며, 값이 없을 경우 기본값은 false입니다.
    @AppStorage("darkModeEnabled") private var isDarkMode = false
    @AppStorage("username") private var username = "Guest"

    var body: some View {
        VStack(spacing: 20) {
            // Toggle 스위치를 누르면 isDarkMode 값이 바뀌고,
            // 그 즉시 UserDefaults에 저장되며, 화면도 새로고침됩니다.
            Toggle(isOn: $isDarkMode) {
                Text("다크 모드")
            }

            // TextField에 글자를 입력하면 username 값이 바뀌고,
            // 즉시 UserDefaults에 저장됩니다.
            TextField("사용자 이름", text: $username)
                .textFieldStyle(.roundedBorder)

            if isDarkMode {
                Text("현재 다크 모드입니다.")
            } else {
                Text("현재 라이트 모드입니다.")
            }
        }
        .padding()
    }
}

 

특징 

- 선언형: @AppStorage 를 변수 앞에 붙여주기만 하면 끝입니다.

- 자동 동기화: @AppStorage 변수의 값이 바뀌면 UserDefaults에 자동 저장되고, @State처럼 뷰를 자동으로 다시 그립니다.

 

 


 

 

세 가지 방법 비교

방법 장점 단점
직접 접근 간단하고 직관적, 모든 종류의 프로젝트에서 사용 가능 SwiftUI 뷰와 연동할 때 onAppear같은 수동 코드 필요
Codable 복잡한 데이터 구조나 객체 배열을 통째로 관리 가능 코드가 비교적 길어지고, 인코딩/디코딩 과정이 추가됨
@AppStorage SwiftUI에 최적화. 코드가 매우 간결하고, 값 변경 시 UI 자동 업데이트 String, Int 등 기본 타입만 지원. Codable 객체는 직접 사용 불가

 

 

 

여기까지 UserDefaults로 데이터를 저장하는 세 가지 방법에 대해 알아보았습니다. 앱의 상황과 데이터의 종류에 따라 가장 적합한 방법을 선택하여 사용해 보시기 바랍니다.