Markus Blog

SwiftUI Toy Project

…where I am building a documentation app using modern SwiftUI.

Goals

  • Get some SwiftUI exercise building a little app from ground up
  • Try out SwiftData hands-on
  • Build UIs dynamically based on a selection of a few UI element options and an external configuration
  • Create equivalent data models in SwiftUI and Django-Rest-Framework and synchronize between them
  • Create an app base for further UI/UX and ML/AI toy projects 😃

The Story

The idea for the app is to support collecting data in a community, big or small or actually just one person, maybe oneself. One user defines a task (or an assignment) and shares it with other users, who then can document having done this task as often as they wish. When defining the task, different basic elements (e.g. enter a number) can be given a meaning and be combined. Definition of the assignment actually happens via Django (the other part of the toy project). The app is for getting jobs done – according to assignments. The information collected about the done job depends on the elements chosen for the assignment. For example:

  • “Take out the garbage” needs no additional elements and is just done. The user who did the job and a timestamp are always part of the recorded information
  • “Price Monitoring” may consist of a selection of products that should be monitored and a number field for the current price of the product. The GPS location is automatically recorded to associate the information with the place to buy from.
  • For a “Warehouse Inventory”, a product barcode scan may be combined with entering the number of items of the product.
  • For “Animal Sightings”, users select the species, optionally specify the number of animals. Timestamp and GPS location are added automatically to complete the done job.
  • In order to document an “Installation”, a photo, timestamp and GPS location may be all that is needed

Takeaways

  • Working with SwiftData is straightforward and can be surprisingly lean. I did spend more time on concurrency than expected (often trying to solve warnings about Non-sendable type). What worked for the scope of my project is: a) decorate all functions accessing the ModelContext with @MainActor and b) make use of await / async whenever possible: e.g. URLSession.shared.data() instead of URLSession.shared.dataTask.
  • Apparently, it is a good idea to declare the data model twice:
    1. once for interacting with the database, e.g. @Model final class ItemModel, and
    2. again as a simple struct for almost anything else: e.g. struct Item with exactly the same properties. Specifically, passing a ItemModel (or a binding to it) on to a child, would freeze the app.
  • Using the new @Observable and @State makes code cleaner and I really liked it at first. But I eventually reverted back to using ObservableObject, @Published and @ObservedObject when I wanted to pass Binding<>s down through child views. For now, I couldnt figure out how to create actually updating Binding<>s with @Observable.
  • In previous projects, I fell back to Objective-C at some point to get the functionality that I wanted. This time, SwiftUI just provided everything.

Helpfull Resources