Getting Started with SwiftData: SwiftUI
One common problem a developer runs into when adding a caching data mechanism to a SwiftUI app using CoreData is the chaotic effort to integrate it into the application. But with the introduction of SwiftData
in iOS 17
, it allows developers to add persistence to their app quickly, with minimal code and no external dependencies.
If you want to know more about different methods to persist data in your app, check this article:-
In this article, we’ll explore how to integrate SwiftData into a SwiftUI app, including setting up the data model, configuring ModelContainer and ModelContext and performing CRUD operations.
Introduction
The SwiftData stack is very similar to the CoreData, but it focuses entirely on code with no external file formats and uses Swift’s new macro system to create a seamless API experience. It is basically a wrapper around CoreData.
Import SwiftData
to integration SwiftData into your SwiftUI application.
Model Creation
If you have used Core Data before, you may remember that you have to create a data model (with a file extension .xcdatamodeld) using a data model editor for data persistence. But here, SwiftData streamlines the whole process with macros.
You just need to add @Model
macro in front of your class declaration to convert a Swift class into a stored model that’s managed by SwiftData.
import SwiftData
// Annotate new or existing model classes with the @Model macro.
@Model
class Trip {
var name: String
var destination: String
var startDate: Date
var endDate: Date
var accommodation: Accommodation?
}
Beyond the @Model macro, SwiftData provides additional macros like @Attribute
and @Relationship
to fine-tune your schema definition.
The @Attribute
macro allows you to add constraints to properties, like making them unique or renaming them. The @Relationship
macro, on the other hand, helps you define relationships between different models and set delete rules.
@Attribute(.unique) var name: String
Relationship(.cascade) var accommodation: Accommodation?
SwiftData persists all non-computed attributes of a model by default, but you may not always want this to happen. For example, one or more properties on a class may only ever contain temporary data that doesn’t need saving, such as the current weather at an upcoming trip’s destination. In such scenarios, annotate those properties with the @Transient()
macro and SwiftData won’t write their values to disk.
@Transient var destinationWeather = Weather.current()
Configuring a ModelContainer
An object that manages an app’s schema and model storage configuration. To set up the default storage, use the modelContainer()
view modifier and specify the array of model types to persist. Model Container is set in WindowGroup
.
import SwiftUI
import SwiftData
@main
struct TripsApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.modelContainer(for: [Trip.self, Accommodation.self])
}
}
}
ModelContext
Once you have set up the model container, you can begin using the model context to fetch and save data. It’s like an object that enables you to fetch, insert, and delete models, and save any changes to disk. Everything in SwiftData happens with model context. It is basically like view context in CoreData.
import SwiftUI
import SwiftData
struct ContentView: View {
@Environment(\.modelContext) private var context
}
Query
With the context, you are ready to fetch data. The simplest way is to use the @Query
property wrapper. You can easily load and filter anything stored in your database with a single line of code.
SwiftData and SwiftUI work together to provide live updates to your views when the underlying data changes, with no need to manually refresh the results.
You can add predicate
to the query
to filter the elements, sort the query, set the order- whether to sort in forward or reverse order and set animation for user interface changes that result from changes to the fetched results.
struct ContentView: View {
@Query(sort: \.startDate, order: .reverse, animation: .smooth) var allTrips: [Trip]
var body: some View {
List {
ForEach(allTrips) {
TripView(for: $0)
}
}
}
}
CRUD in SwiftData
You can use @Query
to read data. To insert an item in the persistent store, you can call the insert method of the model context and pass it the model objects to insert.
var trip = Trip(name: name,
destination: destination,
startDate: startDate,
endDate: endDate)
context.insert(trip)
Similarly, you can delete the item via the model context like this:
modelContext.delete(trip)
Updating is even more simple. You can set the new values for the objects directly. Here is an example where I change the destination of the trip:
trip.destination = "India"
Conclusion
This is a brief introduction of SwiftData. I’ve walked you through defining your data model using SwiftData’s Schema macros to efficiently managing data with ModelContainer and ModelContext, and you’ve seen how SwiftData simplifies data persistence and management.
Thanks for Reading!
Hope, you have found this article useful. If you liked this article, please share and 👏 so other people can read it too.
Follow me at LinkedIn @linkedin.com/in/rohit-13
For reading & learning about these topics, I have found the following articles very useful :-