SwiftData Basic

Một câu hỏi phổ biến trong quá trình phát triển ứng dụng SwiftUI là cách làm việc với Core Data để lưu dữ liệu vĩnh viễn trong ứng dụng. Bất chấp những nỗ lực không ngừng của Apple nhằm đơn giản hóa API của Core Data, những người mới thường thấy khó sử dụng framework này. Tuy nhiên, tại WWDC 2023 Apple đã phát hành một framework mới có tên SwiftData trong iOS 17 để thay thế Core Data. SwiftData được thiết kế để dễ sử dụng hơn cho việc lập mô hình và quản lý dữ liệu, mang đến cách tiếp cận thân thiện hơn với người dùng.

SwiftData là gì?

SwiftData cho phép bạn lưu trữ dữ liệu một cách nhanh chóng, đơn giản với số lượng code tối thiểu.

Sử dụng SwiftData để lưu dữ liệu ứng dụng dưới dạng offline hoặc dữ liệu tạm thời.

Với SwiftData, bạn không cần phải lo lắng về việc kết nối với cơ sở dữ liệu hoặc hiểu SQL để truy xuất các bản ghi dữ liệu. Thay vào đó, bạn có thể tập trung vào làm việc với API và Swift Macros, chẳng hạn như @Query@Model, để quản lý dữ liệu trong ứng dụng của bạn một cách hiệu quả.

Một số tính năng của SwiftData

  • Mô hình hóa dữ liệu khai báo: SwiftData sử dụng mô hình hóa dữ liệu khai báo, có nghĩa là bạn có thể xác định mô hình dữ liệu của mình theo cách dễ đọc và dễ hiểu.
  • Lưu trữ tự động: SwiftData tự động lưu trữ dữ liệu của bạn vào bộ nhớ cơ bản. Điều này có nghĩa là bạn không phải lo lắng về việc viết bất kỳ mã nào để lưu hoặc tải dữ liệu của mình.
  • Truy cập dữ liệu hiệu quả: SwiftData sử dụng các phương pháp truy cập dữ liệu hiệu quả, chẳng hạn như tải chậm, để đảm bảo dữ liệu của bạn được truy cập nhanh nhất có thể.
  • Tích hợp với SwiftUI: SwiftData tích hợp hoàn hảo với SwiftUI, vì vậy bạn có thể sử dụng nó để lưu giữ dữ liệu trong ứng dụng SwiftUI của mình.

Model Creation

  • @Model is a macro giúp cấu hình model schema.
1
2
3
4
5
6
7
@Model class Song {
  var title: String
  var artist: String
  var album: String
  var genre: String
  var rating: Double
}

Có thể thêm marco @Attribute để chỉ định thuộc tính 'name' là duy nhất

1
2
3
4
5
6
7
8
9
@Model class Album {
  @Attribute(.unique) var name: String
  var artist: String
  var genre: String
 
  // The cascade relationship instructs SwiftData to delete all
    // songs when the album is deleted.
  @Attribute(.cascade) var songs: [Song]? = []
}

Model Container

  • Là một object quản lý schema của ứng dụng
  • Model Container có thể được khai báo trong WindowGroup.

Model Container có thể được khởi tạo bằng cách sau

1
2
3
4
5
6
// Basic
let container = try ModelContainer(for: [Song.self, Album.self])
 
// With configuration
let container = try ModelContainer(for: [Song.self, Album.self],
                                    configurations: ModelConfiguration(url: URL("path"))))

Hoặc trong SwiftUI, bạn có thể  khởi tạo Model Container  tại file gốc của ứng dụng

1
2
3
4
5
6
7
8
9
10
11
12
import SwiftData
import SwiftUI
 
@main
struct MusicApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer (for: [Song.self, Album.self]))
    }
}

Model Context

  • Là 1 objects giúp chung ta có thể truy xuất, thêm, sửa, xoá data
  • Mỗi sự kiện đều diễn ra tại model context
  • Tương tự  như view context trong Core Data
1
2
3
struct ContextView: View {
    @Environment(\.modelContext) private var modelContext
}

Query

  • Sử dụng @Query trong SwiftUI views để truy xuất dữ liệu.
  • @Query  đảm bảo views sẽ được tự cập nhật lại mỗi khi dữ liệu thay đổi.
1
@Query(sort: \.artist, order: .reverse) var songs: [Song]

INSERT, UPDATE, DELETE using Model Context

Thêm item vào database

modelContext.insert(song)

Cập nhật item

song.artist ="Sơn Tùng"

Xóa item khỏi database

modelContext.delete(song)

Trong SwiftData, bạn không cần gọi method context.save() nữa vì SwiftData đã tự động lưu dữ liệu khi có sự thay đổi.

Đây là phần giới thiệu ngắn gọn về SwiftData. Nếu bạn vẫn cảm thấy bối rối về cách sử dụng SwiftData thì đừng lo lắng. Bạn sẽ hiểu cách sử dụng nó sau khi xây dựng ứng dụng To Do.

Tạo 1 ứng dụng To Do đơn giản

Bây giờ bạn đã hiểu cơ bản về SwiftData, tôi muốn trình bày cách tạo một ứng dụng việc cần làm đơn giản bằng cách sử dụng framework này. Ứng dụng này không có đầy đủ chức năng và chỉ cho phép người dùng thêm một tác vụ ngẫu nhiên vào todo list. Tuy nhiên, đây là điểm khởi đầu tốt để bạn làm quen với  SwiftData.

swiftui-swiftdata-todo-app

Giả sử bạn đã tạo project SwiftUI trong Xcode, trước tiên hãy tạo mô hình dữ liệu của ứng dụng. Tạo một file mới có tên là ToDoItem và thêm đoạn code sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import Foundation
import SwiftData
 
@Model class ToDoItem: Identifiable {
    var id: UUID
    var name: String
    var isComplete: Bool
 
    init(id: UUID = UUID(), name: String = "", isComplete: Bool = false) {
        self.id = id
        self.name = name
        self.isComplete = isComplete
    }
}

Tiếp theo thêm đoạn code sau để tạo fake data

1
2
3
4
5
6
7
8
func generateRandomTodoItem() -> ToDoItem {
    let tasks = [ "Buy groceries", "Finish homework", "Go for a run", "Practice Yoga", "Read a book", "Write a blog post", "Clean the house", "Walk the dog", "Attend a meeting" ]
 
    let randomIndex = Int.random(in: 0..<tasks.count)
    let randomTask = tasks[randomIndex]
 
    return ToDoItem(name: randomTask, isComplete: Bool.random())
}

Trong file ContentView.swift file, cập nhật đoạn code như sau

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import SwiftData
 
struct ContentView: View {
    @Query var todoItems: [ToDoItem]
 
    var body: some View {
        NavigationStack {
            List {
                ForEach(todoItems) { todoItem in
                    HStack {
                        Text(todoItem.name)
 
                        Spacer()
 
                        if todoItem.isComplete {
                            Image(systemName: "checkmark")
                        }
                    }
                }
            }
 
            .navigationTitle("To Do List")
        }
    }
}

Mảng todoItems  được đánh dấu với @Query property wrapper. Thuộc tính này giúp chúng ta tự động lấy được ToDoItem trong database.

Setup Model Container

Việc tiếp theo chúng ta cần làm là cài đặt Model Container, thêm đoạn code sau vào file ToDoDemoAppApp.swift

1
2
3
4
5
6
7
8
struct ToDoDemoAppApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer(for: ToDoItem.self)
    }
}

Save to-do items into database

Mở file ContentView.swift, thêm dòng code sau

1
@Environment(\.modelContext) private var modelContext

Sau khi khai báo xong modelContext, chúng ta có thể lưu trữ item vào database

1
2
3
4
5
.toolbar {
    Button("", systemImage: "plus") {
        modelContext.insert(generateRandomTodoItem())
    }
}

Để lưu 1 item vào database, gọi method insert trong model context

swiftui-todo-list-model-context

Bạn có thể test với simulator ở chế độ preview bằng cách thêm đoạn code sau

1
2
3
4
#Preview {
    ContentView()
        .modelContainer(for: ToDoItem.self)
}

Khi bạn nhấn vào nút “+”, ứng dụng sẽ ngay lập tức lưu to-do item vào database

Updating an existing item

SwiftData giảm đáng kể khối lượng công việc cần thiết để xử lý việc cập nhật hoặc sửa đổi trong persistent store. Bằng cách chỉ cần đánh dấu các đối tượng bằng macro @Model, SwiftData sẽ tự động sửa đổi các setters để theo dõi và quan sát thay đổi. Điều này có nghĩa là không cần thay đổi code để cập nhật các item

Deleting the item from the database

Mở file ContentView struct, thêm dòng code sau

1
2
3
4
5
6
.onDelete(perform: { indexSet in
    for index in indexSet {
        let itemToDelete = todoItems[index]
        modelContext.delete(itemToDelete)
    }
})

Để xoá 1 item khỏi database, ta gọi đến method delete trong model Context

Summary

Tôi hy vọng rằng bây giờ bạn đã hiểu rõ hơn về cách tích hợp SwiftData vào dự án SwiftUI và cách thực hiện tất cả các thao tác CRUD cơ bản.

References

Getting Started with SwiftData for SwiftUI Development
In iOS 17, Apple releases a new framework called SwiftData. In this tutorial, we will explore this framework for persistent data management and modelling.
SwiftData: Simplifying Persistence in iOS Apps
Learn all about SwiftData, a new framework introduced at WWDC 2023 that provides a Swift-like API for working with persistence in iOS apps and simplifies Core Data usage.

https://developer.apple.com/videos/play/wwdc2023/10154/?time=750
https://developer.apple.com/documentation/swiftdata