in

SwiftUI – List of Timers, getting "index out of range" when deleting timer from list


I’m really struggling with removing a timer from an array of timers, that are being displayed in a list.

I have a Model that stores the timer information. In this simplified example, it is just storing the timeRemaining.

I have a ViewModel that has 2 arrays, one storing Timer Models, and another storing Timers. Also has delete timer, create timer, and append timer array functions in the View Model.

Content View is displaying the timers in a List, using ForEach. It also has a Navigation Bar with an “Add” button at the top for going to another view for setting up the timers.

The User Added Timers View allows users to select the numbers of seconds, then add the timer. The Add button appends the seconds to the Timer Model Array, and adds a Timer to the Timer Array in the view model.

Everything works fine, except when I delete a timer from the list, I get an index out of range in the createTimer() function of the view model. I know what the problem is… I am hard coding the timer index when adding a timer to the Timer array in the User Added Timers view. I just have no idea how to fix it. I have tried for days to find a way of accessing the index of the ForEach and using that as the index for each timer in the Timers Array… but I don’t know if it is even possible to do that?

Anyway, I am completely stuck… any insight would be greatly appreciated.

Thanks in advance!

This code below is very simplified compared to the actual code, but it pinpoints the problem.

Model:

import Foundation
import SwiftUI

struct TimerModel: Identifiable {
   let id = UUID()
   var timeRemainingSeconds: Int
}

ViewModel:

import Foundation
import SwiftUI

class TimerViewModel: ObservableObject {

   @Published var timerModelArray = [TimerModel]()
   @Published var timersArray = [Timer]()

   func deleteItem(indexSet: IndexSet) {
       timersArray.remove(atOffsets: indexSet)
       timerModelArray.remove(atOffsets: indexSet)
   }

   func createTimer(timerNumber: Int) -> Timer {
       return Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { timer in
            self.timerModelArray[timerNumber].timeRemainingSeconds -= 1
       }
   }

   func appendTimerArray(timeRemainingSeconds: Int) {
       timerModelArray.append(TimerModel(timeRemainingSeconds: timeRemainingSeconds))
   }
}

ContentView:

import SwiftUI

struct ContentView: View {

@StateObject var viewModel = TimerViewModel()
@State var arrayCount = 0

var body: some View {
    NavigationView {
        VStack {
            List {
                ForEach(viewModel.timerModelArray.indices, id: .self) { time in
                    Section {
                        Text("(viewModel.timerModelArray[time].timeRemainingSeconds)")
                    }
                }
                .onDelete { indexSet in
                    viewModel.timersArray[viewModel.timersArray.count - 1].invalidate()
                    viewModel.deleteItem(indexSet: indexSet)
                }
            }
        }
        .background(.ultraThinMaterial)
        .listStyle(InsetGroupedListStyle())
        .navigationBarItems(trailing: NavigationLink("Add", destination: UserAddedTimer()))
    }
    .environmentObject(viewModel)
}
}

UserAddedTimerView:

import SwiftUI

struct UserAddedTimer: View {

@EnvironmentObject var viewModel: TimerViewModel

@State var timerSeconds: Int = 0

var body: some View {
    VStack {
        Spacer()
        Stepper(value: $timerSeconds, in: 0...59, step: 1) {
            Text("Seconds: (timerSeconds)")
                .font(.title2)
        }
            .padding()
            .padding(.horizontal, 15)
        Divider()
        Button("Add Timer") {
            viewModel.appendTimerArray(timeRemainingSeconds: timerSeconds)
            viewModel.timersArray.append(viewModel.createTimer(timerNumber: viewModel.timerModelArray.count - 1))
            
        }
        .font(.title2)
        .frame(width: 200, height: 60, alignment: .center)
        .background(.secondary)
        .cornerRadius(10)
        .padding(.top, 40)
        .padding(.bottom, 15)
    }
    .background(.ultraThinMaterial)
}
}



Source: https://stackoverflow.com/questions/70719500/swiftui-list-of-timers-getting-index-out-of-range-when-deleting-timer-from

A camera to capture videos in real time by placing filters using Python with the help of the Tkinter and OpenCV libraries

Google Cloud Spanner Dialect for SQLAlchemy Is Generally Available