SwiftData 스키마 불일치로 ModelContainer 초기화 실패

hyun·2025년 9월 4일
0

iOS

목록 보기
50/54

TimerModel에 createdAt: Date 필드를 추가하고, SwiftDataManager가 직접 ModelContainer를 생성하도록 리팩터링하면서 발생.

앱 실행 하니까 크래시가 뜸 [ fatalError("Failed to create ModelContainer: (error)") ]
결론적으로 시뮬레이터에서 앱 삭제하고 재실행 하니까 해결됨

원인

디스크에 이미 존재하던 SwiftData 스토어의 스키마가 이전 모델 구조를 기준으로 만들어져 있음.
이번 커밋에서 TimerModel에 새 필드(createdAt) 추가 & ModelContainer 생성 방식 변경 → 스키마가 변함
SwiftData가 이 변경을 자동 마이그레이션으로 처리하지 못해 컨테이너 초기화 단계에서 실패.

시뮬레이터에서 앱 삭제 후 재실행하면 기존 스토어가 제거되어 새 스키마로 정상 생성됨
난 그냥 시뮬에서 지웠는데 CLI에서도 가능한가봄

# 부들 ID 바꿔서 실행
xcrun simctl uninstall booted <com.your.bundleid>
# (전체 리셋이 필요할 땐) 모든 시뮬레이터 지우기
xcrun simctl erase all

추가

fetchAll()에서 createdAt 기준 내림차순 정렬을 추가했는데, 기존 레코드에는 createdAt 컬럼 자체가 없음 → 스키마 불일치.
SwiftDataManager가 ModelContainer(for: TimerModel.self, StatsModel.self)를 직접 생성하도록 바꾼 것도 기존 스토어 파일을 그대로 사용하게 만들어 충돌을 더 빨리 드러냄.

교훈

모델 스키마를 바꾸면 디스크 스토어도 같이 생각해야 한다
SwiftData의 자동 마이그레이션은 일부 변경(추가/옵셔널화 등)만 커버하고, 모든 변경을 해결해주지 않는다
개발 단계에선 스토어 초기화 전략을 준비해두면 트러블슈팅 시간이 줄어든다.

재발 방지

컨테이너 생성 실패 시 메모리 스토어로 폴백(개발/테스트 한정)

let schema = Schema([TimerModel.self, StatsModel.self])
do {
  return try ModelContainer(for: schema)
} catch {
  // 디스크 실패 시 메모리로라도 구동
  let mem = ModelConfiguration(isStoredInMemoryOnly: true)
  return try! ModelContainer(for: schema, configurations: mem)
}

단순 필드 추가니까 괜찮겠지라고 생각했다가 컨테이너 초기화에서 막힌 케이스
SwiftData가 모든 변경을 매끈하게 마이그레이션해주진 않으니, 스키마 변경 = 스토어 수명주기 관리라고 항상 같이 생각해야 한다는 걸 깨달음
지금처럼 리스트 정렬 키로 새 필드를 도입할 땐, 구버전 데이터에 대한 기본값/옵셔널 처리 전략을 먼저 세우는 게 안전

0개의 댓글