Contents
Chào mừng bạn đến với Fx Studio. Nhân dịp năm mới, mình sẽ bắt đầu một chủ đề mới tới với bạn. Đó là SwiftData. Đây chính là giải pháp tối ưu và chính chủ Apple dành cho nền tảng SwiftUI trong vấn đề làm việc với cơ sở dữ liệu. Nghe qua cũng hấp dẫn đấy chứ.
Nếu mọi việc đã ổn rồi, thì …
Bắt đầu thôi!
Giới thiệu về SwiftData
SwiftData là một thư viện dữ liệu được phát triển cho ngôn ngữ lập trình Swift. Nhằm giúp các nhà phát triển xây dựng và quản lý dữ liệu một cách dễ dàng và hiệu quả. Với SwiftData, việc tương tác với cơ sở dữ liệu trở nên đơn giản hơn bao giờ hết.
Thư viện này cung cấp một cách tiếp cận linh hoạt và mạnh mẽ để thao tác với các loại cơ sở dữ liệu phổ biến như SQLite, MySQL, PostgreSQL … và nhiều hơn nữa. SwiftData cho phép bạn thực hiện các hoạt động như: query/insert/update/delete … một cách dễ dàng thông qua các phương thức đơn giản và trực quan.
Một trong những điểm nổi bật của SwiftData là khả năng xử lý dữ liệu bất đồng bộ, giúp tăng hiệu suất và đáp ứng nhanh chóng cho ứng dụng của bạn. Ngoài ra, nó cũng hỗ trợ các tính năng như ghi nhật ký, mã hóa dữ liệu và kiểm tra lỗi, giúp bảo mật và đảm bảo tính toàn vẹn của dữ liệu.
Với cú pháp đơn giản và dễ hiểu, nó là một công cụ lý tưởng cho việc xây dựng ứng dụng di động và web đáng tin cậy và mạnh mẽ. Bất kể bạn là một nhà phát triển mới bắt đầu hay một chuyên gia kinh nghiệm, nó sẽ giúp bạn tiết kiệm thời gian và công sức trong việc làm việc với dữ liệu.
Tham khảo thêm tài liệu của Apple về SwiftData nhóe!
Chuẩn bị
Đây là thư viện mới nhất mà Apple giới thiệu tại WWDC23 vừa rồi. Do đó, bạn cần phải chuẩn những công cụ mới nhất để có thể làm việc với nó.
-
- Xcode 15
- Swift 5.9
- SwiftUI 5
- iOS 17.0+
- iPadOS 17.0+
- macOS 14.0+
- tvOS 17.0+
- watchOS 10.0+
- visionOS 1.0+ (beta)
- …
Về mặt kiến thức chuyên môn, bạn cần nắm được lập trình iOS cơ bản hoặc lập trình iOS với SwiftUI. Nếu bạn chưa biết về chúng thì có thể bắt đầu bằng 2 link dưới đây:
Và để trải nghiệm của bạn thật là mới mẻ, nên xem như bạn chưa biết gì về CoreData hay các thư viện tương tự nhóe. Trong bài viết này, mình sử dụng SwiftUI để hướng dẫn & giải thích cho bạn.
Bạn không cần lo lắng quá đâu. Vì nó đơn giản hơn bạn suy nghĩ rất nhiều à.
Data Model
Tạo file
Bắt đầu, bạn hãy tạo mới một Project nhóe. Project này sẽ theo chúng ta trong các bài viết sau nữa. Nội dung của project sẽ làm một ứng dụng Todo List vô cùng đơn giản.
Bạn sẽ thấy rằng phần Storage ta sẽ để là none
. Tức là, bạn không cần quan tâm nhiều về vấn đề tạo các file model để lưu trữ dữ liệu trong ứng dụng.
Với CoreData, bạn cần phải tạo thêm các Data Model (với đuôi mở rộng là
*.xcdatamodel
) & thêm trình chỉnh sửa mô hình dữ liệu trên. Khá là phức tạp!
@Model
Quay lại SwiftData nào! Bây giờ, bạn chỉ cần tạo các Model Class mà thôi. Ví dụ ta sẽ có 1 class TodoItem
như sau:
class TodoItem { var id: UUID var name: String var isComplete: Bool var createDate: Date init(id: UUID = UUID(), name: String = "", isComplete: Bool = false, createDate: Date = Date()) { self.id = id self.name = name self.isComplete = isComplete self.createDate = createDate } }
Nhiệm vụ của bạn sẽ thêm Macro @Model
vào trước từ khóa class
khai báo cho Model Class này.
import SwiftData @Model class TodoItem { var id: UUID var name: String var isComplete: Bool var createDate: Date init(id: UUID = UUID(), name: String = "", isComplete: Bool = false, createDate: Date = Date()) { self.id = id self.name = name self.isComplete = isComplete self.createDate = createDate } }
Trong đó:
- Chú ý thêm
import SwiftData
vào file code - Bạn có thể thêm các thuộc tính liên quan tới việc quan hệ dữ liệu, như
@Attribute
Vậy là xong rồi nhóe!
Model Container
Tiếp theo, bạn sẽ quan tâm tới từ khóa Model Container trong SwiftData. Đây là một Data persistent. Và cũng tương tự với các Data Persistent của CoreData. Nó đóng vài trong cầu nối giữa cơ sở dữ liệu và ứng dụng. Cơ bản ta có 2 cách khởi tạo nó:
// 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"))))
Ở trên là code với Swift, còn với code SwiftUI thì nó đã tích hợp sẵn rồi. Bạn chỉ cần thêm modifier tại root app mà thôi. Xem tiếp ví dụ code cho ứng dụng của chúng ta nha.
import SwiftUI import SwiftData @main struct SwiftDataDemoApp: App { var body: some Scene { WindowGroup { ContentView() } .modelContainer(for: TodoItem.self) } }
Như vậy thôi, ta tiếp tục sang một khái niệm quan trong nữa của SwiftData nhóe!
Model Context
Sau khi đã cài đặt xong các Model Container, bạn sẽ sử dụng Model Context để tương tác dữ liệu. Với các tương tác cơ bản như là: insert/query/update/delete … Một lần nữa, với SwiftUI bạn chỉ cần lấy nó lên từ biến môi trường mà thôi.
struct ContentView: View { ... @Environment(\.modelContext) private var modelContext ... }
Một số thao tác cơ bản như sau:
- Query
@Query(sort: \.artist, order: .reverse) var songs: [Song]
- Insert
modelContext.insert(song)
- Delete
modelContext.delete(song)
Với Update, các Model Context đã tự động đồng bộ dữ liệu khi có bất cứ thay đổi gì tới các đối tượng Model của bạn. Vậy là bạn đã đủ kiến thức rồi đấy, thực hành ngay thôi.
Insert
Tác vụ đầu tiên mà chúng ta thực hiện là thêm một đối tượng vào CSDL nhóe. Để bắt đầu, mình chỉnh sửa lại ContentView
một chút như sau:
struct ContentView: View { var todoItems: [TodoItem] @Environment(\.modelContext) private var modelContext @State var isShowAlert = false @State var taskContent = "" var body: some View { NavigationStack { List { ForEach(todoItems) { item in //Row HStack { VStack (alignment: .leading) { Text(item.name) Text(item.createDate.toString(dateFormat: "yyyy:MM:dd hh:mm:ss")) .fontWeight(.thin) .italic() } Spacer() if item.isComplete { Image(systemName: "checkmark") } } } } // navigation bar .navigationTitle("To do list") // toolbar .toolbar{ Button("", systemImage: "plus") { // random add item //modelContext.insert(Helper.generateRandomToDoItem()) isShowAlert.toggle() } } .alert("Add new task", isPresented: $isShowAlert) { TextField("Content", text: $taskContent) .textInputAutocapitalization(.never) Button("OK", action: { addNewTask() }) Button("Cancel", role: .cancel) { } } } } func addNewTask() { let task = TodoItem(name: taskContent, isComplete: false) modelContext.insert(task) taskContent = "" isShowAlert = false } }
Trong đó:
- Giao diện chính là một
List
đơn giản. - Sử dụng array
todoItems
để lặp và hiện thị dữ liệu lên List - Một Bar Button dùng để hiện một Alert với biến
@State
làisShowAlert
modelContext
được dùng để tương tác dữ liệu
Function addNewTask()
sẽ tạo mới một đối tượng TodoItem và sử dụng modelContext
để đưa nó vào CSDL. Về function cũng khá đơn giản. Bạn chỉ cần quan tâm tới dòng lệnh modelContext.insert(task)
là đủ rồi.
Bạn sẽ nhận ra rằng
try ... catch
đi đâu hết rồi? Đó chính là thế mạnh của SwiftUI kết hợp SwiftData à.
Query
Muốn thấy được dữ liệu mà bạn đã thêm vào CSDL, thì chúng ta sẽ phải lấy chúng nó lên. Hay còn gọi là Fetch Data. Với thư viện mới này, chúng ta được hỗ trợ các Macro để có thể dữ liệu lấy một cách nhanh chóng và đơn giản.
Chỉnh sửa lại một tí phần khai báo cho todoItems
nhóe:
@Query var todoItems: [TodoItem]
Ngoài ra, bạn có thể áp dụng thêm các Filter & Sort cho @Query
, để lấy dữ liệu chuẩn hơn nữa. Tìm hiểu phần này sau ở các bài viết sau nha.
Nhiệm vụ chúng ta lúc này chỉ còn bấm cái nút Reload Preview mà thôi.
EZ Game!
Lưu ý, nếu bạn không thấy Preview thay đổi gì, thì là thiếu Model Container rồi. Do đó, bạn thêm modifier vào Preview, tương tự cách thêm và root app nha.
#Preview { ContentView() .modelContainer(for: ToDoItem.self) }
Update
Tác vụ tiếp theo, chúng ta sẽ thay đổi giá trị thuộc tính của các đối tượng và xem chúng có được đồng bộ vào CSDL không nào. Với project ví dụ này, mình chọn việc tap
vào các Row, thì sẽ thay đổi trạng thái isComplete
từ false
sang true
hoặc ngược lại.
Bạn chỉnh sửa phần ForEach
như sau nha:
ForEach(todoItems) { item in //Row HStack { VStack (alignment: .leading) { Text(item.name) Text(item.createDate.toString(dateFormat: "yyyy:MM:dd hh:mm:ss")) .fontWeight(.thin) .italic() } Spacer() if item.isComplete { Image(systemName: "checkmark") } } // select row .onTapGesture { item.isComplete.toggle() } }
Trong đó:
.onTapGesture
là hàm xử lý cảm ứng cho view- Sử dụng lại đối tượng
item
và thay đổi giá trị củaisComplete
Lần này, bạn cũng không thấy try catch
hay modelContext
đâu nữa. SwiftData đã tự động đồng bộ hết rồi. Khi kết hợp với SwiftUI, nó sẽ đảm bảo tính thống nhất trong tư tưởng lập trình với SwiftUI nói riêng và Declative Programming nói chung.
Bạn tap
vài lần, bật/tắt/build lại trên simulator nhóe. Để cảm nhận kết quả.
Delete
Bạn cũng đoán ra được cái kết cho tác vụ Delete rồi đó. Cũng tương tự với các tác vụ trên. Ta sẽ sử dụng modelContext
để xóa một đối tượng ra khỏi CSDL.
Ví dụ code như sau:
ForEach(todoItems) { item in //Row HStack { VStack (alignment: .leading) { Text(item.name) Text(item.createDate.toString(dateFormat: "yyyy:MM:dd hh:mm:ss")) .fontWeight(.thin) .italic() } Spacer() if item.isComplete { Image(systemName: "checkmark") } } // select row .onTapGesture { item.isComplete.toggle() } } // Delete .onDelete(perform: { indexSet in for index in indexSet { let itemToDelete = todoItems[index] modelContext.delete(itemToDelete) } })
Dùng chính modifier .onDelete
của ForEach. Trong closure đó, ta tiếp tục dùng modelContex
để xóa tiếp đối tượng. Bạn sẽ cảm nhận được:
- Tiếp tục là không cần
try catch
khi tương tác với CSDL - Không cần Fetch/Query lại dữ liệu
- Không cần cập nhật lại UI
Mọi thứ hoạt động một cách tự động với nhau. EZ Game!
Tạm kết
- Tìm hiểu về SwiftData
- Kết hợp với SwiftUI để phát triển ứng dụng có tương tác và lưu trữ dữ liệu
- Thực hiện các thao tác cơ bản với CSDL
Okay! Tới đây, mình xin kết thúc bài viết đầu tiên về SwiftData với SwiftUI . Nếu có gì thắc mắc hay góp ý cho mình, thì bạn có thể để lại bình luận hoặc gửi email theo trang Contact.
Cảm ơn bạn đã đọc bài viết này!
Written by chuotfx
Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!
Leave a Reply Cancel reply
Fan page
Tags
Recent Posts
- CO-STAR – Công thức vàng để viết Prompt hiệu quả cho LLM
- Prompt Engineering trong 10 phút
- Một số ví dụ sử dụng Prompt cơ bản khi làm việc với AI
- Prompt trong 10 phút
- Charles Proxy – Phần 1 : Giới thiệu, cài đặt và cấu hình
- Complete Concurrency với Swift 6
- 300 Bài code thiếu nhi bằng Python – Ebook
- Builder Pattern trong 10 phút
- Observer Pattern trong 10 phút
- Memento Pattern trong 10 phút
Archives
- December 2024 (4)
- September 2024 (1)
- July 2024 (1)
- June 2024 (1)
- May 2024 (4)
- April 2024 (2)
- March 2024 (5)
- January 2024 (4)
- February 2023 (1)
- January 2023 (2)
- November 2022 (2)
- October 2022 (1)
- September 2022 (5)
- August 2022 (6)
- July 2022 (7)
- June 2022 (8)
- May 2022 (5)
- April 2022 (1)
- March 2022 (3)
- February 2022 (5)
- January 2022 (4)
- December 2021 (6)
- November 2021 (8)
- October 2021 (8)
- September 2021 (8)
- August 2021 (8)
- July 2021 (9)
- June 2021 (8)
- May 2021 (7)
- April 2021 (11)
- March 2021 (12)
- February 2021 (3)
- January 2021 (3)
- December 2020 (3)
- November 2020 (9)
- October 2020 (7)
- September 2020 (17)
- August 2020 (1)
- July 2020 (3)
- June 2020 (1)
- May 2020 (2)
- April 2020 (3)
- March 2020 (20)
- February 2020 (5)
- January 2020 (2)
- December 2019 (12)
- November 2019 (12)
- October 2019 (19)
- September 2019 (17)
- August 2019 (10)