TEAM LICENSES: Save money and learn new skills through a Hacking with Swift+ team license >>

SwiftData: passing relationships through several subviews

Forums > SwiftUI

Hey, all.

I'm writing an app that has a fairly linear model with 4 relationships:

Site ->> [Room] ->> [Container] ->> [Items].

Here is a simplified view of the graph (leaving out the reverse relationships for now):

 @Model
 class Site {
     var name: String
     var rooms: [Room]?
 }

@Model
 class Room {
     var name: String
     var containers: [Container]?
 }

 @Model
 class Container {
     var name: String
     var items: [Item]?
 }

@Model
class Item {
    var name: String
 }

On my first view I am using an @Query var sites: Site to grab all the Sites defined in the model. Sites have an optional array of Room. To manage this, I list all the sites in a NavigationStack which leads to an EditSiteView view. This works fine.

@Query var sites: [Site]

var body: some View {
    NavigationStack {
        List {
            ForEach(sites) { site in
                NavigationLink(value: site) {
                    Text(site.name)
                }
            }
            .navigationDestination(for: Site.self, destination: EditSiteView.init)
        }
    }
}

Here's where I'm stuck. The problem is how to create Room links from the site and continue down the chain of relationships.

Firstly, I'm having issues building navigationLinks from the optional array of Room. I've tried a number of way, such as site.rooms?.forEach(), if site.rooms != nil { ForEach(site.rooms) { room in ..., etc. Xcode is grumpy at all these so far.

If the site does have rooms, then I want to build another navigation to pass the selected room to a Room editor view, which would then list any Containers in that room. The same logic ensues until we get down to Items, which are at the bottom of the graph currently.

Along the way I will have the ability to add any newly-created objects to the model. I'd normally do with the modelContext from the Environment. Adding @Environment(\.modelContext) var modelContext at each subview creates all kinds of problem. However I could use an @Bindable to hold the incoming Room from the parent container, right?

In that case, would any changes I make to the room in a Form correctly go "uphill" and update the Room array on the parent Site? It'd be a @Bindable Room pointing back to a @Bindable Site, I think? Will that work? Will any changes I make to the room correctly be applied to site.rooms for the site it belongs to? If that's the case, I wouldn't need the modelContext at all, right?

2      

hi,

Firstly, I'm having issues building navigationLinks from the optional array of Room. I've tried a number of way, such as site.rooms?.forEach(), if site.rooms != nil { ForEach(site.rooms) { room in ..., etc. Xcode is grumpy at all these so far.

just add a computed variable to your view, perhaps of the form

var rooms: [Room] { site.rooms?.sorted(by: { $0.name < $1.name }) ?? [] } // or however you want to sort them ...

and now you can safely write

ForEach(rooms) { room in ... }

to describe the view's body.

hope that helps,

DMG

2      

Thanks, DMG! Any insight on the bigger issue: nested navigation?

2      

Hacking with Swift is sponsored by RevenueCat.

SPONSORED Take the pain out of configuring and testing your paywalls. RevenueCat's Paywalls allow you to remotely configure your entire paywall view without any code changes or app updates.

Learn more here

Sponsor Hacking with Swift and reach the world's largest Swift community!

Reply to this topic…

You need to create an account or log in to reply.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.