Freshly inserted data through REST-request only displayed after reopening the view

I have this JSON-File coming from a MySQL-Database via PHP:

   {
      "id":1,
      "partner":{
         "id":1,
         "name":"Migros Bank",
         "image":"migrosbank"
      },
      "name":"Testkonto 1",
      "type":"bank",
      "iban":"CH12 1234 1234 1234 1234 1",
      "datapoints":[
         {
            "id":1,
            "depot_id":1,
            "date":"2021-12-28",
            "amount":5811.490234375
         },
         {
            "id":2,
            "depot_id":1,
            "date":"2021-12-29",
            "amount":7736.89013671875
         }
      ]
   }

In SwiftUI I decode it to a custom struct called Depot which consists of one instance of the custom struct Partner and an array of Instances of the custom struct Depotstand:

struct Depot: Hashable, Codable, Identifiable {
    var id: Int
    var partner: Partner? = nil
    var name: String
    var type: String
    var iban: String? = nil
    var datapoints: [Depotstand]? = nil
}

struct Partner: Hashable, Codable, Identifiable {
    var id: Int
    var name: String
    var image: String

    var imageName: Image {
        Image(image)
    }
}

struct Depotstand: Hashable, Codable, Identifiable {
    var id: Int
    var depot_id: Int
    var date: Date
    var amount: Double
}

I have a custom class called DataService which handles all the REST-stuff etc. which is referenced in every file/view that uses data from the REST-interface as @StateObject as in:

@StateObject private var DATA = DataService()

The structure is like this:

  1. ContentView.swift (does not include DATA) loads Home.swift
  2. Home.swift (includes DATA) loads DATA on the NavigationView wrapper async via .task (which works great) as in:
NavigationView {
    // some stuff here
}
.task {
    do {
        try await DATA.readDepotAll()
        try await DATA.readDepotstandAll()
    } catch {
        print(error.localizedDescription)
    }
}
  1. Home.swift loads DepotList.swift which shows a list of all Depots of a certain category (a click on a list item opens the view DepotDetails.swift which shows a list of all Depotstands aka datapoints)
  2. In DepotDetails.swift is a + button in the toolbar which activates a sheet to insert a new Depotstand aka datapoint via DepotstandAdd.swift (which also works perfectly). But here is where my actual problem starts; the new datapoint can be inserted and when I print out the most current datapoint's value, the correct amount is displayed. But in the list of datapoints, the new added one is not reflected until I go one page back (DepotList.swift) which makes a refresh and shows the new total amount and then again on DepotDetails.swift which then also shows the refreshed data. I would like the data of DepotDetails.swift to be refreshed on completion of the sheet-action.

I attach the following code, DepotList.swift, DepotDetails.swift and DepotstandAdd.swift, as well as the relevant parts of the DataService which receives and posts the data over REST, since the post is already getting too long - sorry.

Thanks for helping me out!

P.s: To be very clear; there is no error or failure message or something like this - everything just works as expected. I just need to know, how I can get the freshly inserted data to be displayed without having to manually reentering the view to let it doing it itself.

Are you familiar with data dependencies (source of truth) in SwiftUI? Example @State, @StateObject, @ObservedObject, @EnvironmentObject etc.

If anyone of the variables are declared using one of the above, and if their @Published property changes then the views would be refreshed automatically.

IMHO it might make sense to go through https://developer.apple.com/wwdc20/10040

From DepotstandAdd.swift, it looks like you're "adding" the depotstand by telling your server database to add it. If that's correct, then it seems like you will need to also do one of the following 2 things:

  1. Have a mechanism for the server to inform you when the database changes so that you can update your Depot value (in particular, update datapoints in this case), or:

  2. Update datapoints directly in your Swift code when a depotstand is added.

#1 will result in a slight delay before the UI updates, since it involves a round-trip or two to the server to get the updated data. #2 is easier, but there is a small risk that the server update didn't happen, in which case your local data is out of sync with the server. You could do both #1 and #2, to update your local data immediately with what you expect the server to have, then fetch an update from the server and find out what it actually has stored.

Have I understood your question correctly?

Guessing:

  • I think it has something to do with DATA.depot.datapoints. Is Depot a struct or a class?

Just remember:

  • Mutating a class property is not considered as a value change.
  • Mutating a struct property is considered as a value change.

Testing

  • For testing purpose create a temp @Published var temp dataPoints, update it there and see if your view reacts.
  • If so then it is something with Depot and if it is a struct / class.

Possible Workaround

  • You can manually call objectWillChange.send() inside your DataService to indicate the object has changed

I created a TEST-API including all the app-code, so you can see everything in detail and can even post and get data from a test-server to see exactly what's going on. Hope this helps... silvioberger.ch/TEST-API.zip

Since there were no more replies for the last three days, I thought, I could post this update to everyone, instead of just in the direct replies.

I created a TEST-API including all the app-code, so you can see everything in detail and can even post and get data from a test-server to see exactly what's going on. Hope this helps... silvioberger.ch/TEST-API.zip

Any help is greatly appreciated.

Freshly inserted data through REST-request only displayed after reopening the view
 
 
Q