0

I created a View that displays a line graph based on an array of Doubles. The graph struct then divides the view horizontally in order for each of the points to have the same amount of separation. I am using GeometryReader and Path to make the graph. When I load the View with a given array of Doubles it displays correctly.

However, when the data changes, such as adding or removing data, the graph is not updated properly.

As an example using text, this is what the graph looks like normally (Assume it is a line graph): |-_-_-_-_|

When I add a value to the array of Doubles, the graph does appear to show that a new value was added, but the value is not recognized or read. This is what it looks like when a value is added (Again, assume it is a line graph): |-_-_-_-_ |. As you can see, it recognized there is a new value because it allocated space for the new value, but no line was shown, as it most likely does not recognize the added value. When I reload the view, such as by going back and into the view again, the graph is displayed correctly.

The big problem comes when a value is deleted. When a value is deleted, the app crashes with the error Fatal error: Index out of range. When I load the app again the graph is fixed.

I thought there might be something wrong with my deleting, so I created a test file in which I referenced an array of Doubles and buttons to add and remove values from the array, and the same behavior happened. This showed that the values put into the View were not updated properly.

This is the file I created to test the behavior of my graph:

struct GraphTest: View {
  /*Data*/
  @State var data: [Double] = [180, 242, 164, 202, 176, 100]
  var body: some View {
    VStack {
      /*Struct that shows the line graph*/
      LineGraph(data: data)
      .frame(height: 200)
       
      /*Button to remove the last item of array*/
      Button(action: {
        data.removeLast()
      }) {
        Text("Delete")
      }
       
      /*Button to add a value to the end of the array*/
      Button(action: {
        data.append(180)
      }) {
        Text("Add")
      }
    }
  }
}

And this is how I'm setting up my LineGraph struct:

struct LineGraph: View {
  var data: [Double]
  var body: some View {
    GeometryReader { geometry in
    ...

I tried doing data @Bindable in LineGraph, but I could not find a way to do so, as I'm getting the data from a Core Data FetchRequest, but I really do not know what to do from now to fix the issue, as I am relatively new in SwiftUI, and could not find anything similar on the internet.

Any help is appreciated, thank you :)

FrankFabregat2
  • 165
  • 1
  • 1
  • 10

1 Answers1

1

There is not enough code provided in LineGraph, but I assume you have inside something like

ForEach(0..<data.count) { i in // iterating this way result in crash !!
    Text("\(self.data[i])")
}

instead you have to iterate at least like

ForEach(data.indices, id: \.self) { i in     // no crash !!
    Text("\(self.data[i])")
}
Asperi
  • 228,894
  • 20
  • 464
  • 690