Reputation: 1452
I have a form to select some users and assign them a int value.
The model:
class ReadingTime: Identifiable, Hashable {
var id: Int
@State var user: User
@Published var value: Int
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
static func == (lhs: ReadingTime, rhs: ReadingTime) -> Bool {
lhs.id == rhs.id
}
init(id: Int, user: User, value: Int) {
self.id = id
self._user = State(wrappedValue: user)
self.value = value
}
}
The view:
@Binding var times: [ReadingTime]
@State var newUser: User?
func didSelect(_ user: User?) {
if let user = user {
readingTime.append(ReadingTime(id: readingTime.nextMaxId,
user: user,
value: 0))
}
}
// In the body:
VStack(alignment: .leading, spacing: 0) {
HStack {
Picker("Select a user", selection: $newUser.onChange(didSelect)) {
ForEach(users) {
Text($0.name).tag(Optional($0))
}
}
.id(users)
}
VStack(spacing: 8) {
ForEach(0..<times.count, id: \.self) { i in
HStack(spacing: 0) {
Text(times[i].user.name)
TextField("ms", value: $times[i].value, formatter: NumberFormatter())
Button(action: {
NSApp.keyWindow?.makeFirstResponder(nil)
if let index = times.firstIndex(where: { $0 == times[i] }) {
times.remove(at: index)
}
newUser = nil
}, label: {
Text("REMOVE")
})
}
}
}
}
}
}
It looks like this:
However, when deleting an entry in the list, I get this error:
Fatal error: Index out of range: file Swift/ContiguousArrayBuffer.swift
What's going on here?
Upvotes: 9
Views: 19568
Reputation: 357
Since there is no accepted answer:
Don't use the index of your array to get the specific object inside your ForEach. Like you did before, you're able to access your objects without using count. Using count causes your Index out of range error.
Do it like this:
ForEach(times) { time in
// ...
Text(time.user.name)
// ...
}
Upvotes: 0
Reputation: 285140
Modifying the number of items of an array while being enumerated is an evil trap.
0..<times.count
creates a temporary static range.
If you remove the first item in the array index 1 becomes 0, index 2 becomes 1 and so on.
Unfortunately there is no index times.count-1
anymore and you get the Index out of range
crash when the loop reaches the last index.
You can avoid the crash if you enumerate the array reversed.
Upvotes: 7