I have the following simple ContentView:
struct ContentView: View {
@State private var matrix = [BoxModel(id: 0), BoxModel(id: 1), BoxModel(id: 2)]
@State private var chosen = BoxModel(id: -1)
var body: some View {
NavigationView {
GeometryReader { geometry in
ScrollView {
VStack {
let columns = [GridItem(.fixed(50), spacing: 0),
GridItem(.fixed(50), spacing: 0),
GridItem(.fixed(50), spacing: 0)]
LazyVGrid(columns: columns, spacing: 0 ) {
ForEach(matrix) { box in
Button {
chosen = box
} label: {
Text("\(box.number)")
}
}
}
.padding()
Button {
chosen.number = 5
} label: {
Text("Click Me")
}
}
}
}
}
}
}
where the BoxModel is an object like this:
struct BoxModel: Codable, Identifiable, Hashable {
var id: Int
var number: Int
}
When the button is pressed I want the "box" to be updated with the new number. But I want to do this without using the index. I know that if I get the index of the box, I can do something like matrix[0].number = 5 and it'll work.
Is this possible?
CodePudding user response:
Your code shows boxes that are contained in the matrix
array, while you have also created chosen
which is a completely different instance.
You change chosen
to store 5 in the "number" property, and I bet it's changing, but you are still only showing in the UI the instances of the boxes that are inside the matrix
array, whatever happens to chosen
will not be seen on the screen.
You need to completely drop the chosen
variable, and have a button that changes each instance of "box" that is in the matrix
. You might want to move your code inside the ForEach
to another view too; that view would have a @State
var of type BoxModel
of its own, so you can see the changes as they happen.
CodePudding user response:
Like the answer I gave you in your previous question, you could use a ObservableObject
like in this example code:
class BoxModel: ObservableObject {
@Published var matrix: [Box] = [Box(id: 0, number: 0),Box(id: 1, number: 1), Box(id: 2, number: 2)]
func updateBox(_ box: Box) {
if let ndx = matrix.firstIndex(where: { $0.id == box.id }) {
matrix[ndx] = box
}
}
}
struct Box: Codable, Identifiable, Hashable {
var id: Int
var number: Int
}
struct ContentView: View {
@StateObject var boxModel = BoxModel()
@State private var chosen = Box(id: -1, number: 0)
var body: some View {
NavigationView {
GeometryReader { geometry in
ScrollView {
VStack {
let columns = [GridItem(.fixed(50), spacing: 0),
GridItem(.fixed(50), spacing: 0),
GridItem(.fixed(50), spacing: 0)]
LazyVGrid(columns: columns, spacing: 0 ) {
ForEach(boxModel.matrix) { box in
Button {
chosen = box
} label: {
Text("\(box.number)")
}
}
}
.padding()
Button {
chosen.number = 5
boxModel.updateBox(chosen)
} label: {
Text("Click Me")
}
Text("chosen number: \(chosen.number)").padding(20) // <-- for testing
}
}
}
}
}
}
If you definitely do not want to use ObservableObject such as in the code, let me know and I'll delete my answer.