Post

Replies

Boosts

Views

Created

Error when calling function to move an element: "Cannot use mutating member on immutable value: 'self' is immutable"
Hi, The goal is the move an element based on an input matrix using timer to trigger changes in the position. Say we have 2 positions, an input matrix and the element that is to be moved defined: import SwiftUI import Foundation // Positions struct PositionConstants { static let pos_1 = CGPoint(x: 155, y: 475) static let pos_2 = CGPoint(x: 135, y: 375) } // Input Matrix struct Input { static let input_1: [[Int]] = [ [ 1, 1, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 1, 0, 1, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], [ 0, 0, 0, 0, 0, 0, 0, 0, 0 ], ] } // Element Class class Element: ObservableObject { let imageName: String let name: String let size: CGSize @Published var position: CGPoint init(imageName: String, name: String, size: CGSize, position: CGPoint) { self.imageName = imageName self.name = name self.size = size self.position = position } } Moving the element without a function works perfectly fine: struct Pos_View: View { @ObservedObject var element_1 = Element(imageName: "pic_1", name: "", size: CGSize(width: 100, height: 100), position: PositionConstants.pos_1) let Input_Matrix = Input.input_1 // Index to track current row in matrix @State private var currentIndex = 0 // Timer to trigger updates private let timer = Timer.publish(every: 1.0, on: .main, in: .common).autoconnect() var body: some View { VStack { // Display element Image(element_1.imageName) .resizable() .frame(width: element_1.size.width, height: element_1.size.height) .position(element_1.position) .onReceive(timer) { _ in // Update element position based on matrix if currentIndex < Input_Matrix.count { let isFirstElementOne = Input_Matrix[currentIndex][0] == 1 let newPosition = isFirstElementOne ? PositionConstants.pos_2 : PositionConstants.pos_1 withAnimation { element_1.position = newPosition } currentIndex += 1 } else { // Stop the timer when we reach the end of the matrix timer.upstream.connect().cancel() } } } } } struct ContentView: PreviewProvider { static var previews: some View { Pos_View() } } But when using a function to trigger the animation, I get the error "Cannot use mutating member on immutable value: 'self' is immutable" when calling the function using a button: struct Pos_View: View { @ObservedObject var element_1 = Element(imageName: "pic_1", name: "", size: CGSize(width: 100, height: 100), position: PositionConstants.pos_1) let Input_Matrix = Input.input_1 // Index to track current row in matrix @State var currentIndex = 0 // Timer to trigger updates private var timer: Timer? var body: some View { VStack { // Display element Image(element_1.imageName) .resizable() .frame(width: element_1.size.width, height: element_1.size.height) .position(element_1.position) // Button to start animation Button("Start Animation") { startAnimation() } } } mutating func startAnimation() { currentIndex = 0 // Reset index before starting animation timer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true) {timer in if self.currentIndex < self.Input_Matrix.count { let isFirstElementOne = self.Input_Matrix[self.currentIndex][0] == 1 let newPosition = isFirstElementOne ? PositionConstants.pos_2 : PositionConstants.pos_1 withAnimation { self.element_1.position = newPosition } self.currentIndex += 1 } else { // Stop the timer when we reach the end of matrix timer.invalidate() } } } } struct ContentView: PreviewProvider { static var previews: some View { Pos_View() } } The function is defined as mutating and the element as as @ObservedObject. Anyone has a clue?
3
0
676
Apr ’24