SwiftData 에 대해서 알아보자

SwiftData는 WWDC2023에서 소개된 최신 데이터 관리 프레임워크이다. SwiftData는 기존에 자주 사용했던 CoreData를 기반으로 하지만 Swift 언어를 활용해 CoreData보다 훨씬 쉽고 직관적인 기능을 제공한다.

https://developer.apple.com/documentation/swiftdata

 

SwiftData | Apple Developer Documentation

Write your model code declaratively to add managed persistence and efficient model fetching.

developer.apple.com

 

먼저 SwiftData는 Swift의 속성래퍼를 활용해 데이터 모델을 정의한다. @Model 을 사용해 클래스를 모델로 선언할 수 있고 이 방법은 기존 CoreData의 복잡한 설정 과정을 쉽게 만들어 준다는 장점이 있다.

 

또한 예제에서 볼 내용과 같이 SwiftUI와 완벽하게 통합되어있어 데이터 변경 사항을 자동으로 UI에 반영할 수 있고 @Query 속성 래퍼를 사용해서 직접적으로 데이터를 가져올 수 있다.

 

이 쿼리를 활용해서 필터링, 정렬, 관계 등 쉽게 구현이 가능하다는 점이 특징 🙂

 

이후에 CloudKit과 동기화까지 쉽게 구현할 수 있어 여러 기기 간 데이터 일관성을 유지할 수 있다

 

이렇게 알아보니 SwiftUI를 쓰면서 CoreData보다 훨씬 쉽게 로컬 저장소를 사용할 수 있다는게 참 편하고 좋았다!

예제를 통해 SwiftData를 보다 쉽게 이해해보자!

 

예제는 List를 활용해서 간단한 TodoList를 만들어 보려고 한다

import Foundation
import SwiftData

@Model
class TodoList {
    let title: String
    let subtitle: String
    let date: Date
    
    init(title: String, subtitle: String, date: Date) {
        self.title = title
        self.subtitle = subtitle
        self.date = date
    }
}

먼저 model을 구현해주어야하는데 @Model을 사용해 SwiftData에 담겨질 데이터 모델링을 쉽게 선언해줄 수 있다.

@main
struct ToDoSwiftUIApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(for: TodoList.self)
    }
}

그 다음 메인 App에서 .modelContainer를 선언해 데이터 모델이 저장되고 관리될 수 있는 컨테이너에 넣어준다.

struct ContentView: View {
    @Environment(\\.modelContext) var context
    @State var newTodo = ""
    
    @Query var todoList: [TodoList]
    
    var body: some View {
        NavigationView {
            VStack {
                TextField("오늘 할일을 추가해 주세요.", text: $newTodo)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                
                Button("추가하기") {
                    guard !newTodo.isEmpty else {
                        return
                    }
                    
                    let newTodo = TodoList(title: newTodo, subtitle: "추가", date: Date())
                    
                    context.insert(newTodo)
                }
                
                List {
                    ForEach(todoList) { todo in
                        Text(todo.title)
                        Text(todo.subtitle)
                        Text(todo.date.formatted())
                    }
                    .onDelete(perform: { indexSet in
                        indexSet.forEach { index in
                            context.delete(todoList[index])
                        }
                    })
                }
                .overlay {
                    if todoList.isEmpty {
                        Text("오늘 등록한 일정이 없습니다.")
                    }
                }
            }
            .navigationTitle("TodoList")
        }
    }
}

그 다음 데이터를 넣어주고 SwiftData가 저장될 수 있도록 구현해보자

@Environment(\\.modelContext) var context
@State var newTodo = ""

@Query var todoList: [TodoList]

Environment 를 활용해 ModelContext를 구현하고 데이터 베이스와 상호 작용을 관리하는 컨텍스트를 구현해 변경 사항을 추적하고 저장한다.

그 다음 새로운 값을 넣어줄 newTodo를 State를 활용해 구현하고 데이터를 검색하고 필터링할 수 있도록 데이터 모델을 Query를 활용해 모델을 연결한다.

TextField("오늘 할일을 추가해 주세요.", text: $newTodo)
    .textFieldStyle(RoundedBorderTextFieldStyle())

Button("추가하기") {
    guard !newTodo.isEmpty else {
        return
    }
    
    let newTodo = TodoList(title: newTodo, subtitle: "추가", date: Date())
    
    context.insert(newTodo)
}

텍스트 필드를 활용해 새로운 Todo값을 넣어줄 수 있도록 하고 값을 넣은 뒤 버튼을 클릭해 해당하는 데이터를 context.insert를 통해 값이 SwiftData에 들어갈 수 있도록 구현한다.

이렇게 구현하면 값이 로컬에 저장되게 된다! 코어데이터만 사용하다가 이렇게 쉽게 데이터 저장 구현이 되니까 참 신기하기도 하고 역시 이럴때가 제일 재밌다.