0

Edited to remove unneccesary code...

I'm trying to build a view in my app which will display a schedule (for practicing musical instruments). The schedule can have multiple sessions, and each session multiple slots. I am retrieving a 2d array of these slots from Realm and then using a foreach inside another foreach to display each session with its contents. I'm using @EnvironmentObject to access Realm from each view and realm assembles a new [[Slot]] each time any information is changed (which it seems to be doing correctly).

The issue I'm having is that, although it is refreshing the sessions when I add/remove them, it is not updating the contents of each session. Realm is correctly working correctly, but the sub view is not being updated. If I exit and re-enter the ScheduleView it will show correctly again. I have tried various things to get it updating correctly, including changing an @State variable in each view after a delay, but nothing so far has worked and I'm starting to pull my hair out!

struct SessionRow: View {
    @State var sessionNumber: Int
    @State var session: [Slot]
    var delete: () -> Void
    var addSlot: () -> Void
    @State var refreshToggle = false
    
    var body: some View {
        VStack{
            HStack{
                Text("Session \(sessionNumber + 1)")
                Button {
                    self.delete()
                } label: {
                    Label("", systemImage: "trash")
                }
                .buttonStyle(PlainButtonStyle())
                Button {
                    self.addSlot()
                } label: {
                    Label("", systemImage: "plus")
                }
                .buttonStyle(PlainButtonStyle())
            }
            ForEach(0..<self.session.count, id: \.self) { slotNumber in
                SlotRow(slot: self.session[slotNumber], ownPosition: [self.sessionNumber, slotNumber])
            }
            .onDelete { indexSet in
                //
            }
        }
        .onAppear{
            print("Session Number: \(sessionNumber) loaded.")
        }
    }
}

    
    func addSlot(sessionNumber: Int){
        DispatchQueue.main.async {
            self.realmManager.addSlot(sessionNumber: sessionNumber)
            self.refreshToggle.toggle()
            schedule = realmManager.schedule
        }
    }
    
    func deleteSession(at offsets: IndexSet){
        DispatchQueue.main.async {
            self.realmManager.deleteSession(sessionNumber: Int(offsets.first ?? 0))
            schedule = realmManager.schedule
        }
    }
}

struct SlotRow: View {
    
    //@EnvironmentObject var realmManager: RealmManager
    @State var slot: Slot
    //@Binding var isPresented: Bool
    //@Binding var slotPosition: [Int]
    @State var ownPosition: [Int]
    // Add position/session to allow editing? 
    
    var body: some View {
        VStack{
            HStack{
                Text("Own Position: [\(ownPosition[0]),\(ownPosition[1])]")
            }
        }
        .padding()
        .frame(height: 80.0)
        .onAppear{
            print("Slot \(ownPosition) loaded.")
        }
    }
    
    func deleteIntervalFromSlot() {
        //realmManager.updateSlot(session: ownPosition[0], position: ownPosition[1], interval: nil)
    }
}

As you can see I've tried all sorts of hacks to get it to update, and loads of this code is unnecessary and will be removed once I have a solution. I thought I would leave it here to show the sort of things which have been tried.

  • In `ScheduleView` you have a `@State` var `schedule`. Remove that and use only `schedule` from your `RealmManager` – burnsi Jun 18 '22 at 09:59
  • Cheers for the reply. I’ve tried that and it’s having the exact same behaviour. But that’s a good point. What I’ve posted here would never work! – stevednick Jun 18 '22 at 10:02
  • Please show where `realmManager` is created and injected. – burnsi Jun 18 '22 at 10:06
  • Done (hopefully that's what you need to see?). Cheers! – stevednick Jun 18 '22 at 11:33
  • That's quite a bit of code for us to parse through and it doesn't appear you've done any troubleshooting (?) e.g. Add a breakpoint to your code and run; step through it line by line, observing vars and code execution. When you spot something that isn't expected, update the question with that and where it occurred. Additionally, I would expect there to be an [ObservedResults or ObservedRealmObject](https://www.mongodb.com/docs/realm/sdk/swift/swiftui/#views-and-observed-objects) as that object is what updates when Realm changes and therefore updates the associated view. What is RealmManager? – Jay Jun 18 '22 at 12:45
  • Consider the problem might be a known NavigationLink issue, see https://stackoverflow.com/a/61234030/4465531. – Norman Jun 18 '22 at 16:21

1 Answers1

0

I've found the solution, and apologies for the outrageous amount of detail above. I will go back and tidy the above when I get some time.

The issue is that I defined when passing the [Slot] to the session row the variable receiving it was @State and it should just be a var.

struct SessionRow: View {
   
   @State var sessionNumber: Int
   @State var session: [Slot]

Change it to

struct SessionRow: View {
   
   var sessionNumber: Int
   var session: [Slot]

and it works just fine.

A silly error from someone who is new to SwiftUI!