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 aboutNon-sendable type
). What worked for the scope of my project is: a) decorate all functions accessing theModelContext
with@MainActor
and b) make use ofawait
/async
whenever possible: e.g.URLSession.shared.data()
instead ofURLSession.shared.dataTask
. - Apparently, it is a good idea to declare the data model twice:
- once for interacting with the database, e.g.
@Model final class ItemModel
, and - again as a simple struct for almost anything else: e.g.
struct Item
with exactly the same properties. Specifically, passing aItemModel
(or a binding to it) on to a child, would freeze the app.
- once for interacting with the database, e.g.
- Using the new
@Observable
and@State
makes code cleaner and I really liked it at first. But I eventually reverted back to usingObservableObject
,@Published
and@ObservedObject
when I wanted to passBinding<>
s down through child views. For now, I couldnt figure out how to create actually updatingBinding<>
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.