I encountered a problem while using ScrollView in SwiftUI. When I perform a refresh, the app crashes. I access the array using an index in a ForEach loop. This is done to create new data from the array in a commonly used view. The function to create data is adopted from a protocol in the view model. I access it by index because the type of the array is not specified; each view using it may have a different data type. Below is an example code. Is it possible to access data from the array using an index? Every time I refresh, I get an "index out of range" error.
import SwiftUI
struct ContentView: View {
@StateObject var viewModel = ViewModel()
var body: some View {
ScrollView {
if !viewModel.testValues.isEmpty {
LazyVStack(spacing: 20) {
ForEach(Array(zip(viewModel.testValues.indices, viewModel.testValues)), id:\.1) { index, data in
test(index: index, data: data, viewModel: viewModel)
.onAppear {
if !viewModel.isLoading, viewModel.testValues.count - 2 == index {
viewModel.fetch()
}
}
}
}
} else {
Text("tesetsetsetsettse")
}
}
.onAppear {
viewModel.fetch()
}
.refreshable {
viewModel.refresh()
}
}
}
struct test: View {
let index: Int
let data: String
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack(spacing: 8) {
test1(index: index, data: data, viewModel: viewModel)
Text("------------------------")
}
}
}
struct test1: View {
let index: Int
let data: String
@ObservedObject var viewModel: ViewModel
var body: some View {
VStack {
Text(viewModel.testValues[index])
.font(.system(size: 12))
.foregroundStyle(Color.red)
.padding(.horizontal, 40)
.padding(.vertical, 50)
.background {
RoundedRectangle(cornerRadius: 20)
.fill(Color.blue)
}
}
}
}
class ViewModel: ObservableObject {
@Published var isLoading = false
@Published var testValues: [String] = []
func fetch() {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.testValues += [
UUID().uuidString,
UUID().uuidString,
UUID().uuidString,
UUID().uuidString,
UUID().uuidString,
UUID().uuidString,
UUID().uuidString,
UUID().uuidString,
UUID().uuidString,
UUID().uuidString,
]
}
}
func refresh() {
testValues = []
fetch()
}
}