In the example below I want to modify the struct in an array that is used to generate a view from that view. It results in an obvious error (in ForEach the reference to the currently processed item is a let constant). How else I can modify the original array row upon interaction with the view at runtime? In other words, how do I store/pass a reference to the corresponding array item?
I also tried passing the array index to inside the view and accessing it there directly by array[index].someproperty
. It worked great... until I tried deleting rows. In such case the dynamic views no longer contain correct indexes and it generally leads to out of range errors.
In the example below I want to save drag location to the original array rather than to the view itself so that I can conduct logic on it later (can't iterate through views, but can easily iterate over their underlaying array). Could someone point me to the right approach? Thanks!
EDIT: Clarification: The goal here is for the drag gesture to write values to the ballStorage object's array and have generated views react accordingly. But it needs to know which row to modify!
import SwiftUI
let screenWidth = UIScreen.main.bounds.size.width
let screenHeight = UIScreen.main.bounds.size.height
struct SingleBall: Identifiable {
var id = UUID()
var position = CGPoint.zero
}
class BallStorage: ObservableObject {
@Published var balls: [SingleBall] = [
SingleBall(position: CGPoint(x: 110, y: 220)),
SingleBall(position: CGPoint(x: 150, y: 120)),
SingleBall(position: CGPoint(x: 200, y:160)),
SingleBall(position: CGPoint(x: 200, y: 200))
]
}
struct StartScreen: View {
@StateObject var ballStorage = BallStorage()
var body: some View {
ZStack { // stack of balls
ForEach(ballStorage.balls, id: \.id) {
ball in
littleBall(id: ball.id).position(ball.position).gesture(DragGesture()
.onChanged {
gesture in
ball.position = gesture.location //ERROR! can't modify ball (it's a let constant)
}
)
}
}.frame(width:screenWidth, height:screenHeight) //end stack balls
}
}
struct test_Previews: PreviewProvider {
static var previews: some View {
StartScreen()
}
}
EDIT: Another thing I tried was passing 'ball' (see the code) to inside the view. I can modify it there, and the view reacts to the changes, but in this case what gets passed is a copy of the array item, not a reference to the actual struct in the original array. So modifying the array has no effect on views.