[🔫트러블슈팅] 01. ModelContainer 충돌 문제

2025. 10. 31. 15:15·🔫 트러블슈팅

 안녕하세요 NBS 팀의 iL 입니다! 드디어 우리 호우관성의 첫 문서군요.. 트러블슈팅 고!

 

문제

문제 1. SwiftData로 데이터를 처리(CRUD)하던 중 아래와 같은 Log와 함께 크래시가 발생

SwiftData error: Attempt to use ModelContext from a different container

 

문제 2. 메모리 초과, SQLite lock 관련 에러 발생

 

문제 3. 여러 곳에서 동시에 호출 시 동시성 문제 발생

 

분석
public enum AppGroupContainer {
  public static func createShareModelContainer() -> ModelContainer? {
    let appGroupID = "Team ID"
    let schema = Schema([LinkItem.self, HighlightItem.self, CategoryItem.self])
    
    guard let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupID) else {
      print("Error: Failed to get container URL for App Group ID: \(appGroupID)")
      return nil
    }
    
    let storeURL = containerURL.appendingPathComponent("Nbs_store.sqlite")
    let configuration = ModelConfiguration(schema: schema, url: storeURL)
    
    do {
      return try ModelContainer(for: schema, configurations: [configuration])
    } catch {
      print("Error creating ModelContainer: \(error)")
      return nil
    }
  }
}


 우리 앱은 App Group을 통해 ShareExtension <-> SafariExtension <-> App 사이의 통신을 하고 있었습니다. 세 환경이 동일한 DB(Nbs_store.sqlite)를 공유해야 했기 때문에, App Group의 컨테이너 경로를 활용하는 AppGroupContainer를 별도로 생성해서 단일 DB 접근이 가능하도록 설계했습니다. 

 

 이때, AppGroupContainer 내부에서는 팩토리 메소드 패턴을 사용해 ModelContainer를 생성하도록 구현했습니다. 팩토리 메소드 패턴은 코드 구조를 단순하게 유지할 수 있었지만, 결과적으로 CRUD 처리를 수행할 때마다 새로운 ModelContainer 인스턴스가 생성되는 문제가 있었습니다.

 

 SwiftData에서 ModelContainer는 앱의 presistent store를 관리하는 핵심 객체로, 일반적으로 앱 전체에서 단일 인스턴스로 유지되어야 합니다. 그러나 여러 ModelContainer가 동일한 App Group 경로의 DB 파일을 동시에 참조하면서, 스토어 접근 충돌과 컨텍스트 간 불일치가 발생했습니다.

 

해결

  ModelContainer는 앱 전체에서 단 하나만 존재해야하는 객체이기 때문에, 매번 재생성하면 크래시가 발생하므로 싱글톤으로 수정해서 문제를 해결했습니다

 

 SwiftData 공식 가이드 문서에서는 명시적으로 "단일 인스턴스만 사용하라"고 문서화하지는 않았지만, 여러 문서에서 단일 인스턴스를 사용하는 것을 권장한다는 것을 내용을 바탕으로 문제를 해결했습니다. 

 

public enum AppGroupContainer {
  public static let shared: ModelContainer = {
    let appGroupID = "Team ID"
    let schema = Schema([ArticleItem.self, HighlightItem.self, CategoryItem.self])
    
    guard let containerURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: appGroupID) else {
      fatalError()
    }
    
    let storeURL = containerURL.appendingPathComponent("Nbs_store.sqlite")
    let configuration = ModelConfiguration(schema: schema, url: storeURL)
    
    do {
      return try ModelContainer(for: schema, configurations: [configuration])
    } catch {
      fatalError()
    }
  }()
}

 

참고자료

https://stackoverflow.com/questions/78052704/swiftdata-redundant-modelcontainer-instances-causing-data-constraint-loss

"While the documentation says that an app "must have at least one" container it also recommends that you use the .modelContainer modifier so that the container is shared for all your views.

 

https://medium.com/@mrdanteausonio/how-to-access-swift-data-model-context-outside-of-view-hirearchy-using-a-data-service-8508f7a94683

'🔫 트러블슈팅' 카테고리의 다른 글

[🔫 트러블슈팅] 02. LinkNavigator item 디코딩 시 Base64 문자열 처리 오류  (0) 2025.11.07
'🔫 트러블슈팅' 카테고리의 다른 글
  • [🔫 트러블슈팅] 02. LinkNavigator item 디코딩 시 Base64 문자열 처리 오류
ADA-iL
ADA-iL
ada13team 님의 블로그 입니다.
  • ADA-iL
    호우관성
    ADA-iL
  • 전체
    오늘
    어제
    • 분류 전체보기 (3)
      • 📝 개발 문서 (0)
        • iOS (0)
        • MacOS (0)
        • TCA (0)
        • Safari (0)
        • Framework (0)
      • 🔫 트러블슈팅 (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
ADA-iL
[🔫트러블슈팅] 01. ModelContainer 충돌 문제
상단으로

티스토리툴바