I can't find way to delete from a dynamic array that is being used in a ForEach loop. I've been looking with no luck. Many answers use List or don't have a binding in their ForEach. And I don't want to use list because it's hard to fully customize its design.
Below is a sample code that adds and remove elements from an array. This array is used to display a dynamic list of players.
Removing a player produces an index out of range after unwrapping the optional in ForEach loop.
import SwiftUI
struct GameRecapView: View {
@State private var game = Game(players: [Player(name: "Steph"),Player(name: "Kim")])
@State private var shape = Shape.circle
var body: some View {
VStack {
ForEach(self.game.players ,id: \.id) { player in
PlayerView(
player: self.$game.players[self.game.players.firstIndex(where: {$0.id == player.id})!],
shape: self.$shape)
}
Spacer()
Button(action: {
self.toggleShape()
}) {
Text("Change shape")
}
HStack {
Button(action: {
self.addPlayer(player: Player(name: "Eddye"))
}) {
Text("+")
}
Button(action: {
self.removeLastPlayer()
}) {
Text("-")
}
}
}
}
func toggleShape(){
if self.shape == .circle {
self.shape = .square
} else {
self.shape = .circle
}
}
func addPlayer(player : Player) {
self.game.players.append(player)
}
func removeLastPlayer(){
self.game.players.removeLast()
}
func removeItems(at offsets: IndexSet) {
self.game.players.remove(atOffsets: offsets)
}
}
struct PlayerView: View {
@Binding var player : Player
@Binding var shape : Shape
var letters = ["a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t"]
var body: some View {
VStack {
ZStack{
Text(String(self.player.name.first!.uppercased()))
if shape == .square {
Rectangle().stroke().frame(width: 50, height: 50)
} else {
Circle().stroke().frame(width: 50, height: 50)
}
}
Button(action: {
self.player.name = self.letters.randomElement()!
}) {
Text("Change Name")
}
}
}
}
struct Game {
var players : [Player]
}
struct Player : Identifiable {
var id = UUID()
var name : String
}
enum Shape {
case
circle ,
square
}
struct GameRecapView_Previews: PreviewProvider {
static var previews: some View {
GameRecapView()
}
}