I’ve defined a view in SwiftUI which takes an Int array and is supposed to display the elements of the array in a VStack such that every "full row" contains three elements of the array and then the last "row" contains the remainder of elements. When running the app on iOS16 I get "Fatal error: Can’t remove first element from an empty collection" for the call let die = dice.removeFirst()
(also when passing in a non-empty array of course). I’ve tried following the debugger but I don’t understand the way it jumps around through the loops.
On iOS15 this code worked fine. In the actual program I don’t display the array content as Text but I have images associated with each Int between 1 and 6 which I display. I replaced this with Text for simplicity’s sake.
Thanks for any help!
struct DiceOnTableView: View {
let diceArray: [Int]
var body: some View {
let fullRows: Int = diceArray.count / 3
let diceInLastRow: Int = diceArray.count % 3
var dice: [Int] = diceArray
VStack {
ForEach(0..<fullRows, id: .self) { row in
HStack {
ForEach(0..<3) { column in
let die = dice.removeFirst()
Text("(die)")
}
}
}
HStack {
ForEach(0..<diceInLastRow, id: .self) { column in
let die = dice.removeFirst()
Text("(die)")
}
}
}
}
}
2
Answers
This does kind of work on iOS 15 (but strangely – the order of the dice is unexpected), and crashes on iOS 16. In general, you should not be using
var
s in SwiftUI view building code.Your code can be modified to compute the index into the original
diceArray
from therow
,fullRows
, andcolumn
values:The
ForEach
View will crash if you use it like a for loop with dynamic number of items. You need to supply it an array of item structs with ids, e.g. one that isIdentifiable
, e.g.And perhaps use a Grid instead of stacks.