Skip to main content
  1. Blog/

Simple SwiftData

app programming Swift Talk Dim Sum
Phil Chu
Author
Phil Chu
Making software since the 80s

I spent the past week updating my Swift code to the latest and greatest. In some cases it didn’t simplify much ( Observable), but I was able to remove a bunch of SQLite.swift code and replace it with just a few lines of SwiftData.

That code implemented the favorite feature in Talk Dim Sum, where you mark your favorite dishes and see only those in a separate view. Whereas before I stored the IDs of the favorited dishes in a table and wrote functions to insert, search for, and delete those entries, with SwiftData I defined a very simple persistent model containing that ID.

@Model
class Favorite {

    @Attribute(.unique) var id: String

    init(dish: Item) {
        self.id = dish.id
    }
}

Then add a modelContainer in the main view of the app that contains favorites.

 var body: some Scene {
        WindowGroup {
            AppView()
                .modelContainer(for: [
                    Favorite.self
                ])
                .environment(dimsum)
                .environment(places)
                .environment(tts)
                .environment(stt)
                .environment(router)
        }
    }

To favorite a dish, just perform the insert on an environment object.

struct FavoriteButton: View {

    @Environment(\.modelContext) private var context

    let dish: Item

    var body: some View {
        ActionButton("dish.favorite", "heart") {
            context.insert(Favorite(dish: dish))
        }
    }
}

To delete, access the stored favorites using @Query, and once I’ve found the one that matches the dish I want to unfavorite, call delete on the environment object.

struct RemoveFavoriteButton: View {

    @Environment(\.modelContext) private var context

    @Query() var faves: [Favorite]

    let dish: Item

    var body: some View {
        ActionButton("dish.unfavorite", "heart.fill") {
            let found = faves.filter { $0.id == dish.id }
            context.delete(found[0])
        }
    }
}

And to display the list of favorites, just use that @Query and map the Favorites back to dishes (here I do some filtering to remove any obsolete IDs, as it’s possible for dishes to be removed or have their IDs changed).

struct FavoritesCollectionView: View {

    @Environment(DimSum.self) var dimsum: DimSum
    @Query() var faves: [Favorite]

    var body: some View {
        DishCollectionView(dishes: faves.filter({dimsum.isDish($0.id)}).map { dimsum[$0.id]! })
    }
}