프로젝트 맥락
본 글은 Apple Developer Academy_Challenge 2에서 개발한 ‘Re:ToU(오늘의 너)’ 앱을 기반으로 작성되었습니다.
Re:ToU는 사용자의 회고 데이터를 기기 내부에 저장하는 구조를 채택했기 때문에,
데이터의 종류에 따라 어떤 저장 방식을 선택할지가 앱의 설계 품질을 결정짓는 중요한 요소였습니다.
기능 설명
Re:ToU에서는 회고(Reflection) 데이터를 저장해야 했고, 이때 다음과 같은 세 가지 저장 방식이 후보가 되었어요.
- UserDefaults: 단순한 키-값 저장
- FileManager: 직접 파일 생성/읽기
- CoreData: 관계형 데이터베이스 기반 저장
시도 동기
처음에는 가볍게 데이터를 저장하고 불러오기만 하면 될 것 같아서 UserDefaults를 고려했지만,
회고 데이터는 감정/내용/날짜 등 구조화된 정보가 있고,
추후 확장 가능성을 고려했을 때 단순 키-값 저장으로는 한계가 보였어요.
이후 FileManager와 CoreData 중 어떤 게 더 적절할지 비교하고 선택하게 되었어요.
세 가지 저장 방식 비교
UserDefaults / FileManager / CoreData
구조화 데이터 저장 | ❌ 단일값만 | ✅ 직접 인코딩 필요 | ✅ 자동 처리 |
검색/필터링 | ❌ 불가 | ❌ 직접 구현 | ✅ 강력한 쿼리 지원 |
모델 구조 관리 | ❌ 없음 | ✅ 직접 관리 | ✅ 모델 정의 가능 |
난이도 | ✅ 매우 쉬움 | ⚠️ 중간 | ⚠️ 중간~높음 |
확장성 | ❌ 낮음 | ⚠️ 제한적 | ✅ 높음 |
실제 선택:
FileManager + Codable
Re:ToU는 앱 전체 흐름이 간단하고, 회고 항목은 하루 1건 정도로 데이터량이 적기 때문에
복잡한 관계형 DB까지는 필요 없다고 판단했어요.
struct Reflection: Codable, Identifiable {
var id: UUID
var date: Date
var content: String
var emotion: String
}
ReflectionStorage라는 클래스를 통해 파일 입출력을 담당했고,
JSON 형식으로 저장되도록 구현했어요:
func saveToDisk() {
let encoder = JSONEncoder()
if let data = try? encoder.encode(reflections) {
let url = getFileURL()
try? data.write(to: url)
}
}
문제 발견 & 해결
문제해결 방법
파일 깨짐, 인코딩 오류 | Codable 명확히 정의 + 예외 처리 추가 |
디버깅 시 파일 저장 경로 추적 어려움 | FileManager.default.urls(for:in:) 활용 |
데이터 필터링/정렬 직접 처리해야 함 | ViewModel에서 filter { } 및 sorted { } 구현 |
느낀 점
저장 방식은 단순히 작동하느냐가 아니라, 앱의 구조와 목적에 따라 가장 적합한 것을 선택하는 것이 중요하다는 걸 깨달았습니다.
Re:ToU의 경우 복잡한 쿼리나 관계형 모델이 필요하지 않아 FileManager + Codable 방식이 오히려 유지보수에 유리했고,
이후 CoreData로 전환하더라도 명확한 구조를 바탕으로 자연스럽게 마이그레이션할 수 있도록 구성할 수 있었습니다.
'iOS & SwiftUI' 카테고리의 다른 글
단방향 데이터 흐름(One-way Data Flow) 완전 정복 — SwiftUI 실습 예제와 설계 원칙 (3) | 2025.08.14 |
---|---|
SwiftUI 상태 관리 완전 정복기 (3) | 2025.08.13 |
SwiftUI에서 앱 실행 시 인증 흐름 설계하기 (자동 잠금 / 해제 타이밍) (2) | 2025.06.18 |
SwiftUI에서 Face ID / Touch ID 인증 구현하기 (1) | 2025.06.15 |
SwiftUI에서 TextEditor 커스터마이징과 UX 개선 팁 (0) | 2025.06.12 |