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
và @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.
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
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
https://developer.apple.com/videos/play/wwdc2023/10154/?time=750
https://developer.apple.com/documentation/swiftdata