ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • SwiftData 기본 사용법 Model, ModelContext, Query
    개발/Swift 2025. 5. 8. 09:03

    엔티티 정의

    @Model
    final class User: Identifiable {
        var name: String
        var email: String
        @Attribute(.externalStorage) var imageData: Data?
        
        init(name: String, email: String, imageData: Data? = nil) {
            self.name = name
            self.email = email
            self.imageData = imageData
        }
    }
    
    

    @Attribute 매크로 써서 외부 저장소에 저장가능

    • 좀 느리지만 큰 데이터 다루는 용도
    • 일반적인 내부데이터는 SQLite DB 사용하지만 이것은 Document 폴더에 들어간다고 함
      • externalStorage 실제 경로 ⇒ 앱의 Documents 디렉토리 내 별도 폴더
        • ~/Library/Application Support/[앱 번들 ID].store/external_storage/
      • 일반 데이터 (ex> name, email ) ⇒ 앱의 Application Support 디렉토리에 저장됨
        • ~/Library/Application Support/[앱번들ID].store/

    context

    CRUD 작업을 가능하게 하는 객체

    @Environment(\\.modelContext) private var context
    

    일반적으로 view에서는 위와 같이 매크로를 통해 쉽게 접근 가능함

    근데 초기에 model container 세팅해줘야함

    WindowGroup {
        ContentView()
    }
    .modelContainer(for: User.self) // SwiftData의 저장소 시스템을 초기화하고 활성화
    

    데이터 타입이 여러개라면 schema에 넣어주면됨,

    그외 버전관리, 옵션 config 세팅도 가능함

    private var modelContainer: ModelContainer = {
        let schema = Schema([User.self]) //여기 다른 타입 추가
        let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
        do {
               return try ModelContainer(for: schema, configurations: [modelConfiguration])
           } catch {
               fatalError("Could not create ModelContainer: \\(error)")
           }
    }()
    
    WindowGroup {
            MyPageView(store: Store(initialState: .init(), reducer: { AppCoordinator()}))
        }
        .modelContainer(modelContainer)
    
    

    Query

    @Query private var users: [User] 
    private var user: User? {
      users.first
    }
    

    위와같이 단일 데이터만 필요한 경우에도 배열로 쿼리가가능

    • Reducer 에서는 불러올수 없었음, 이외 ViewModel이나 Repository 파일 같이 분리된 파일도 마찬가지임

    → SwiftUI.View 에서만 동작함 , modelContext 도 마찬가지로 View에서만 불러올수 있음

    Accessing Environment<ModelContext>'s value outside of being installed on a View. This will always read the default value and will not update.
    

    디자인 패턴 or 아키텍쳐 적용시 ModelContext 를 VM이나 RP에 전달하여 사용할수있겠지만 (or Reducer)

    이러 저러한 문제가 발생할수 있으며 Query 매크로 자체를 못쓰기 때문에

    Query 매크로 등등 이점을 활용하기가 어려워짐, 따라서 View에서 그냥 접근하는게 낫다고 판단이 됨.

    정렬

        @Query(sort: \\Keyword.date, order: .reverse) private var keywords: [Keyword]
    
    

    날짜 오름차순 정렬인경우 위와같이 하면됨

    \.date 키패스로 접근하려했지만 Cannot infer key path type from context; consider explicitly specifying a root type 이런 에러가 발생하여 명시적으로 타입을 넣어줌

     

    실시간 데이터

    Query로 불러온 데이터가 저장을 통해 새로운 데이터가 들어왔을떄 API나 coredata 같은 경우는 refresh를 통해 새로운 값을 다시 불러와야했다.

    @Query private var users: [User] 
    
    

    근데 쿼리를 사용하면 알아서 실시간 데이터를 대응해줌

    “ObservableObject와 Publisher를 사용하여, 데이터베이스의 변경을 감지하면 뷰를 다시 그리도록 트리거합니다” 라고 함

     

    데이터 수정

    @Query private var users: [User] 
    private var user: User? {
      users.first
    }
    @Environment(\\.modelContext) private var context
    
    

    위와같이 간편하게 context 가져옴

    func editUser() {
    	user?.name = "james"
    	try? context.save()
    }
    

    user.name 을 변경하면 메모리 차원에서 변경이 적용됨, (ex>페이지 떠있을떄)

    context.save() 하는 순간 영구 저장소에 저장 (커밋) 됨

    아주 쉽고 간편하게 변경이 됨

    파라미터를 던져주는것도 아닌데 어떻게 변경된것을 알고 저장할까?

    class ModelContext {
        // 내부적으로 이런 식의 변경사항 추적
        private var changedObjects: Set<PersistentModel>
        private var insertedObjects: Set<PersistentModel>
        private var deletedObjects: Set<PersistentModel>
    }
    
    // 사용 예시
    @Environment(\\.modelContext) private var context
    
    func example() {
        let user = User(name: "Kim")
        context.insert(user)        // insertedObjects에 추가
        
        user.name = "Park"         // changedObjects에 추가
        
        context.delete(user)       // deletedObjects에 추가
        
        try? context.save()        // 모든 변경사항 한번에 저장
    }
    

    이러게 변경 사항들을 보관하고있다가 일괄 저장 한다 함

    댓글

Designed by Tistory.