지난 시간 우리가 만든 투두리스트 앱은 데이터를 따로 저장하지는 않기 때문에 앱을 다시 실행하면 기존의 데이터가 지워집니다.
이번 글에서는 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로 데이터를 저장하는 세 가지 방법에 대해 알아보았습니다. 앱의 상황과 데이터의 종류에 따라 가장 적합한 방법을 선택하여 사용해 보시기 바랍니다.
'SwiftUI 독학으로 기본기 익히기' 카테고리의 다른 글
| 06. 할 일 완료 처리 기능 구현하기 (1) | 2025.10.31 |
|---|---|
| 05. 새로운 할 일 추가 기능 구현 (0) | 2025.10.30 |
| 04. 투두리스트 화면과 내비게이션 구현하기 (0) | 2025.10.29 |
| 03. 로또 번호 생성기 앱 만들기 (0) | 2025.10.28 |
| 02. Text 수정하고 Image 추가하기 (0) | 2025.10.28 |