Reputation: 171
I try this solution of using Grid layout.
We want to display dynamically Array Items in a Grid and if the Array.count Changed an error with Index out of Range comes up and the App crashes.
How to fix this?
var totalrows: Int{
let t = Double(self.cards.count) / Double(self.cols)
return Int(round(t))
}
var cols: Int{
let col = self.verticalSizeClass == .compact ? 4 : 2
return col
}
func colrow (col: Int , row: Int) -> Int{
var colrow = 0
colrow = (row * self.cols) + col
return colrow
}
let cards = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"]
var body: some View {
VStack{
ForEach(0..<self.totalrows,id:\.self) { row in
HStack {
ForEach(0..<self.cols,id:\.self) { column in
Text(self.cards[self.colrow(col: column, row: row)])
}
}
}
}
}
Upvotes: 0
Views: 514
Reputation: 5115
If you add custom safe subscript you'll be able to replace index out boudns array elements with anything you like using nil coalescing.
extension Array {
subscript(guarded idx: Int) -> Element? {
guard (startIndex..<endIndex).contains(idx) else { return nil }
return self[idx]
}
}
Then you could rewrite Text
view like this to display hyphens for invalid indexes and have no crashes.
//...
ForEach(0..<self.cols,id:\.self) { column in
Text(self.cards[guarded: self.colrow(col: column, row: row)] ?? "-")
}
//...
Upvotes: 0
Reputation: 9434
An easy way to avoid any indexOutOfBounds is just to check if the index is out of bounds before doing the operation...
So make this change:
ForEach(0..<self.cols,id:\.self) { column in
let card = self.colrow(col: column, row: row)
if (card < self.cards.count) {
Text(self.cards[card])
}
}
This will leave your last row potentially unfilled but it shouldn't crash
Upvotes: 2
Reputation: 6029
The way you have cols
return either 4 or 2, you will have to have an even count
in cards
.
I would solve this by always checking the count
of cards
and adding an empty item to the end if not already even.
Example:
//only even numbers count
var cards = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"]
if (cards.count % 2) != 0 {
cards.add("")
}
Upvotes: 0