|
import SwiftUI
let shortNames = ["None", "HFC227EA", "TCE1112", "F134A", "HCFC142B", "TCE111", "TFACTONE"]
private var yValues: [Double] = []
struct ContentView: View {
@State private var yScale: Double = 0
@State private var selectedFile = "None"
@State private var fullFileName = "None"
@State private var specs = [Spec]()
@State private var npts: Int = 0
var body: some View {
VStack(alignment: .leading) {
Picker("Select short name:", selection: $selectedFile) {
ForEach(shortNames, id: \.self) { fileName in
Text(String("\(fileName)"))
}
}
.padding()
List () {
Text(fullFileName)
Text(String("y-Scale = \(yScale)"))
Text(String("Number of points in yDdata = \(npts)"))
Text(String("Y-value = \(yValues[5])"))
}
}
.onChange(of: selectedFile) { _ in
fullFileName = selectedFile + ".JSON"
specs = load(fullFileName)
npts = specs[0].yData.count
yScale = specs[0].yScale /* Scaling factor for decompressing absorbance yData */
yValues = [Double] (repeating: 0, count: npts)
yValues = calcAbsorb( npts: npts, yScale: yScale, yData: specs[0].yData )
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
// Function to fill "yData" array with scaled absorbance values
// First make a new, Double array called "yValues"
func calcAbsorb(npts: Int, yScale: Double, yData: [Int] ) -> [Double] {
for ii in 0...(npts-1) {
yValues[ii] = Double(yData[ii]) / yScale
}
return yValues
}
Suspect that the array "yValues" not being passed to View closure? What am I doing wrong?
|
|
Try this
func calcAbsorb(npts: Int, yScale: Double, yData: [Int] ) -> [Double] {
var yValues = [Double]()
for ii in 0...(npts-1) {
// check that number of elements in yData has more then (npts-1)
guard ii < yData.count else { continue }
yValues.append(Double(yData[ii]) / yScale)
}
return yValues
}
|
|
Thanks @NigelGee. Definitely should have included the Guard statement. But that is not the origin of the error. When I set a breakpoint (debugging) after the last line of code in the .onChange closure, I can see that yValues has the correct number of elements with the correct values. For whatever reason, yValues is not updating in Some View. I'm struggling with Declarative coding as my background has been Imperative code.
|
|
You initialize yValues with an empty array:
private var yValues: [Double] = []
But in the body of your ContentView , you access the 5th index of the array:
Text(String("Y-value = \(yValues[5])"))
yValues is empty at that point, so of course your code crashes.
You need to account for an empty array in your code or make sure the array is never empty.
|
|
Yes, yValues is empty when I define the array. But in the .onChange closure, the array yValues is dimensioned and filled with Doubles. Do I need to first initialize yValues with enough elements (i.e., some number greater than npts) and fill with zeros? Or is it inappropriate to display yValues in Some View?
|
|
But in the .onChange closure, the array yValues is dimensioned and filled with Doubles.
But onChange isn't fired until the value of selectedFile changes, which hasn't happened yet when the View first loads.
Do I need to first initialize yValues with enough elements (i.e., some number greater than npts) and fill with zeros?
You need to account for an empty array in your code or make sure the array is never empty.
Or is it inappropriate to display yValues in Some View?
I'm not sure what exactly its purpose is there, so I can't really answer that.
(BTW, The name of the View you are displaying this stuff in is actually ContentView . some View is the data type returned by the body computed property of ContentView , not the name of a View .)
|
|
OK. Makes perfect sense now. Thank you.
|
|
You could put this around Text(String("Y-value = \(yValues[5])"))
if yValues.isEmpty == false {
Text(String("Y-value = \(yValues[5])"))
}
Now will not be called until the .onChange is called. You might want to add && yValues.count >= 6 to the if statement just to make sure that element 5 is there!
|
|
@NigelGee- As you suggested, wrapping
Text(String("Y-value = \(yValues[5])"))
in a conditional was part of the solution. I also had to re-arrange some of the code to update ContentView AFTER filling the yValues array. I do appreciate the assistance from both you and @roosterboy. As an aside and to give some perspective on my programming experience, I was programming in Fotran for many years. I guess that officially makes me old ;-)
|