Skip to main content
506

Using SwiftData with SwiftUI

Created
Active
Last edited
Viewed 1k times
1 min read
Part of Mobile Development Collective
12

One thing we iOS developers should rejoice about is the development of SwiftData, at least if you are coding for a very new project and can forget about iOS versions below 17.

We finally have an encapsulations (of sorts) of the more complex Core Data engine , and it even integrates seamlessly with our Beloved SwiftUI.

In essense,

SwiftData is a powerful and expressive persistence framework built for Swift. We’ll show you how you can model your data directly from Swift code, use SwiftData to work with your models, and integrate with SwiftUI.

import SwiftData

@Model
class Hiking {
    var start: Date
    var end: Date
    var distance: Double
}

There you have a class that has all the main database "CRUD" operations: Create, Read, Update and Delete.

SwiftData model Queries Wrappers

SwiftData includes the @Query macro as a new property wrapper meant specifically for SwiftData.

struct HikingListView: View { 
    @Query (sort, .started) var hikings: [Hiking]

    body: some View {
        ForEach(hikings) {
        // Show off your outdoors and active lifestyle here </joke>
        }
}

Every view can have as many query properties as it needs. Under the hood it uses the ModelContext of the view as its source of data.

This ModelContext comes from the ModelContainer. Each SwiftUI app must provide at least one ModelContainer as an environment variable.

import SwiftData

@mainstruct SwiftHikingApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
        .modelContainer (for: Hiking.self, Location.self  )
    }
}

Let’s say you also want to highlight specific locations in a hiking, we could use the following code:

import SwiftData

@Modelclass Hiking {
    var start: Date
    var end: Date
    var distance: Double
    @Relationship(deleteRule: .cascade) var locations: [Location] = []
}

@Modelclass Location {
    var name: String
    var images: [Strings]
}

This way, simply creating or removing a location takes effect immediate in your app:

ForEach(hikings) { hiking in
    VStack {
        Text(hiking.description)
        Spacer()
        ForEach(hiking.locations) { location in 
            NavigationLink { destination in
                DestinationRow(destination)
            } { Text("67% complete") }  
        }
    }
    //**************************************
    .onDelete(perform: { indexSet in
        if let index = indexSet.first {
            hiking.locations.remove(at: index
        )
    }
    // *************************************}
}  

Notice how we only need to remove a Location from the Hikings arrays of them. This can make your life much easier but it's important to focus on small details, since merely removing a location from a hiking model will remove it from the database.

Compare it with the snipped where we delete a hiking:

private func deleteHiking(_ indexSet: IndexSet) { 
    for index in indexSet {
        let hiking = hikings[index]
        modelContext.delete(hiking)
    }
}

That's how easy it is to use the basic functions of SwiftData. Don't forget to declare the relationships between Hiking and locations. It's a great choice to store data if you only need to support iOS 16 or newer. It may not be such a great choice if you need all the functionalities and robustness of CoreData, some of which are probably not available for SwiftData as of yet.

Originally posted on my medium account, a bit polished before posting it here.

1
  • 4
    I think still too early to adopt SwiftData, a VIPER architecture is more reliable. A good practice is always supporting at least two versions Bellow, like iOS 15 nowadays, so, if your project is completely new and should be done in a couple of years, maybe adopt SwiftData is a good thing, but, for current projects, I wouldn't rush to adopt this feature. Commented Apr 25, 2024 at 12:07