Binding a Textfield to a name in a Object

Hello everybody,

Im new to Swift programming or app programming in geenrell and now im working on my first project. However im struggling right now with something. I crated an object for my Quizzplayer. To give them a name I want to create a textfield for each one of them where the user can enter the name. let me give u a code snippet for my quizPlayer object:

class QuizPlayer: ObservableObject { @Published var name: String @Published var points: Int @Published var isActive: Bool

init(name: String) {
    self.name = name
    self.points = 0
    self.isActive = false
}

func addPoints(pointsToAdd: Int) {
    self.points += pointsToAdd
}

func changeName(newName: String) {
    self.name = newName
}

}

I create 5 empty Quizzplayers at the beginning:

@State private var quizPlayers: [QuizPlayer] = Array(repeating: QuizPlayer(name: ""), count: 5)

then I create my Textfields and try to bind dem to the names of the players:

ForEach(0 ..< self.numberOfPlayers, id: .self) { index in TextField("Player (index + 1) name", text: self.$quizPlayers[index].name) .padding() }

But it's not working at all. very time I run the simulator and edit one textfield, every textfield gets changed so I can't edit them individually. I´m not sure if I used the State and ObservableObject right or what the issue is. Maybe someone understands my problem and can help me.

All the best

Leon

Hi Leon,

I noticed you're making an array of quizPlayers using Array(repeating: QuizPlayer(name: ""), count: 5)

Instead, try this:

@State private var quizPlayers: [QuizPlayer] = Array(repeating: (), count: 5).map { QuizPlayer(name: "")}

Using map will ensure they are all unique since right now it is creating clones of the same player that have the same ID, which is why you are seeing the text fields all get filled at the same time.

You have two problems in your code. First, the @State property wrapper is for structs, not classes. You need to use the @StateObject property wrapper for classes. Either use @StateObject in the view or make QuizPlayer a struct instead of a class and remove @Published from the QuizPlayer fields.

Second, you are overcomplicating things with binding a player's name to a text field. Instead of accessing the players using an index, go through the array of players and bind each player's name to the text field. The code will look similar to the following:

ForEach(quizPlayers, id:\.self) { $player in
  TextField("Player Name: ", text: $player.name)
}

The $player argument gives you the current player so you do not have to access the quizPlayers array or deal with array indexes.

Keep in mind I typed the code from memory so I cannot guarantee it will work correctly if you copy and paste it in your code. You may need to change $player to player. But the code gives you an idea of what you need to do to bind the player's name to the text field.

Binding a Textfield to a name in a Object
 
 
Q