Skip to content
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Fx Studio
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
SwiftData
Written by chuotfx on January 1, 2024

SwiftData – Hello world!

iOS & Swift . SwiftUI

Contents

  • Giới thiệu về SwiftData
  • Chuẩn bị
  • Data Model
    • Tạo file
    • @Model
  • Model Container
  • Model Context
  • Insert
  • Query
  • Update
  • Delete
  • Tạm kết

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:

    • Lập trình iOS cho mọi người
    • Làm quen với SwiftUI

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.

SwiftData

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.

SwiftData

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ủa isComplete

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!

FacebookTweetPinYummlyLinkedInPrintEmailShares70

Related Posts:

  • Flutter
    Cài đặt Flutter SDK & Hello world
  • SwiftData
    SwiftData - Sorts & Filters
Tags: SwiftData, SwiftUI
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

Your email address will not be published. Required fields are marked *

Donate – Buy me a coffee!

Fan page

Fx Studio

Tags

Actor Advanced Swift AI api AppDistribution autolayout basic ios tutorial blog ci/cd closure cocoapod collectionview combine concurrency crashlytics dart dart basic dart tour Declarative delegate deploy design pattern fabric fastlane firebase flavor flutter GCD iOS MVVM optional Prompt engineering Prompt for Coding protocol Python rxswift Swift Swift 5.5 SwiftData SwiftUI SwiftUI Notes tableview testing TravisCI unittest

Recent Posts

  • Prompt for Coding – Code Translation Nâng Cao & Đối Phó Rủi Ro và Đảm Bảo Chất Lượng
  • Tại sao cần các Chiến Lược Quản Lý Ngữ Cảnh khi tương tác với LLMs thông qua góc nhìn AI API
  • Prompt for Coding – Code Translation với Kỹ thuật Exemplar Selection (k-NN)
  • Mô phỏng chiến lược SNOWBALL giúp AI “Nhớ Lâu” hơn trong cuộc trò chuyện
  • Prompt for Coding – Bug Detection với prompting cơ bản
  • Cẩm Nang Đặt Câu Hỏi Chain of Verification (CoVe): Từ Cơ Bản Đến Chuyên Gia
  • Chain of Verification (CoVe): Nâng Cao Độ Tin Cậy Của Mô Hình Ngôn Ngữ Lớn
  • Mixture of Thought (MoT) – Từ Suy Luận Logic đến Ứng Dụng Sáng Tạo
  • Prompt Injection (phần 2) – Chiến Lược Phòng Thủ và Kỹ Thuật Giảm Thiểu Rủi Ro
  • Prompt Injection (phần 1) – Phân Tích về Các Kỹ Thuật Tấn Công

You may also like:

  • Cài đặt Flutter SDK & Hello world
    Flutter
  • SwiftData - Sorts & Filters
    SwiftData

Archives

  • August 2025 (3)
  • July 2025 (10)
  • June 2025 (1)
  • May 2025 (2)
  • April 2025 (1)
  • March 2025 (8)
  • January 2025 (7)
  • 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)

About me

Education, Mini Game, Digital Art & Life of coders
Contacts:
contacts@fxstudio.dev

Fx Studio

  • Home
  • About me
  • Contact us
  • Mail
  • Privacy Policy
  • Donate
  • Sitemap

Categories

  • Art (1)
  • Blog (58)
  • Code (11)
  • Combine (22)
  • Flutter & Dart (24)
  • iOS & Swift (102)
  • No Category (1)
  • RxSwift (37)
  • SwiftUI (80)
  • Tutorials (98)

Newsletter

Stay up to date with our latest news and posts.
Loading

    Copyright © 2025 Fx Studio - All rights reserved.