SwiftUI - Binding eines Textfield zu Listenelementen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • SwiftUI - Binding eines Textfield zu Listenelementen

    Hallo,

    ich versuche gerade eine sehr einfache Liste mit Spielern zu erstellen.
    In meinem SplitView werden die einzelnen Spieler in einer Liste angezeigt. Wenn man einen Spieler antippt, gelangt man auf die Detailseite.
    Jeder Spieler wird als "struct" aufgerufen und die Liste mit allen Spielern wird in einem "class"-Objekt gehalten.
    Es funktioniert auch alles ohne Einwände.

    Allerdings möchte ich gerne, dass im Detailview jeweils ein Textfield für den Vornamen und den Nachnamen angezeigt werden. Wenn ich Änderungen im Textfield vornehme, sollen die Änderungen unmittelbar in der Auswahlliste mit allen Spielern sichtbar werden.
    Ich habe es mit verschiedenen Formen des Bindings (State, StateObject, etc) probiert. Bin aber kläglich gescheitert.

    Vielleicht ist mein Gedankengang auch falsch und Eingaben im Textfield können nicht direkt an die Spieler in der Listenansicht gebunden werden?
    Vielleicht passt auch meine Konstruktion mit den struct für Spieler und der class für die Liste nicht?

    Über einen "Save"-Button und die direkte Übergabe der eingegebenen Informationen an den ausgewählten Spieler ist es mir gelungen. Ich möchte aber gerne auf den Button verzichten.

    Die PlayersList wird als EnvironmentObject behandelt, weil ich die Liste auch in anderen Views der gesamten App benötige.

    Vielleicht kann hier jemand einem Anfänger weiterhelfen.

    Danke im Voraus.


    Quellcode

    1. //
    2. // PlayerData.swift
    3. import Foundation
    4. import SwiftUI
    5. struct Player: Identifiable, Codable, Hashable {
    6. var id = UUID()
    7. var firstName: String
    8. var lastName: String
    9. }
    10. @MainActor class PlayersList: ObservableObject {
    11. @Published var players = [Player]() {
    12. didSet {
    13. if let encoded = try? JSONEncoder().encode(players) {
    14. UserDefaults.standard.set(encoded, forKey: "Players")
    15. }
    16. }
    17. }
    18. init() {
    19. if let savedItems = UserDefaults.standard.data(forKey: "Players"){
    20. if let decodedItems = try? JSONDecoder().decode([Player].self, from: savedItems) {
    21. players = decodedItems
    22. return
    23. }
    24. }
    25. players = []
    26. }
    27. }
    28. //
    29. // PlayerAddView.swift
    30. //
    31. import SwiftUI
    32. struct PlayerAddView: View {
    33. @EnvironmentObject var playersList: PlayersList
    34. @Environment(\.dismiss) var dismiss
    35. @State private var firstName = ""
    36. @State private var lastName = ""
    37. var body: some View {
    38. NavigationStack {
    39. Form{
    40. TextField("First Name", text: $firstName)
    41. TextField("Last Name", text: $lastName)
    42. }
    43. .navigationTitle("Add new Player")
    44. .toolbar{
    45. Button("Cancel") {
    46. dismiss()
    47. }
    48. Button("Add") {
    49. let player = Player(firstName: firstName, lastName: lastName)
    50. playersList.players.append(player)
    51. dismiss()
    52. }
    53. }
    54. }
    55. }
    56. }
    57. struct PlayerAddView_Previews: PreviewProvider {
    58. static var previews: some View {
    59. PlayerAddView()
    60. .environmentObject(PlayersList())
    61. }
    62. }
    63. //
    64. // PlayerDetailView.swift
    65. //
    66. import SwiftUI
    67. struct PlayerDetailView: View {
    68. var player: Player?
    69. var body: some View {
    70. if player != nil {
    71. Text("Hallo \(player!.firstName) \(player!.lastName)")
    72. // Hier soll ein Textfeld hin, welches z.B. den Vornamen des Spielers beinhaltet. Bei Änderungen im Texrfeld soll die Änderung direkt in der Auswahlliste sichtbar werden, ohne dass man über einen "Save"-Button die Änderung "aktiv" an den Spieler übergibt.
    73. }
    74. else {
    75. VStack {
    76. Image(systemName: "person.fill")
    77. Text("Select Player")
    78. }
    79. }
    80. }
    81. }
    82. struct PlayerDetailView_Previews: PreviewProvider {
    83. static var previews: some View {
    84. PlayerDetailView(player: Player(firstName: "TestVorname", lastName: "TestNachname"))
    85. }
    86. }
    87. //
    88. // ContentView.swift
    89. //
    90. import SwiftUI
    91. struct ContentView: View {
    92. @StateObject var playersList = PlayersList()
    93. @State private var showingAddPlayer = false
    94. @State private var selectedPlayer: Player?
    95. var body: some View {
    96. NavigationSplitView {
    97. List(selection: $selectedPlayer){
    98. ForEach(playersList.players) { player in
    99. NavigationLink("\(player.firstName) \(player.lastName)", value: player)
    100. }
    101. .onDelete(perform: removePlayer)
    102. }
    103. .navigationTitle("Player")
    104. .toolbar{
    105. EditButton()
    106. Button{
    107. showingAddPlayer = true
    108. } label: {
    109. Image(systemName: "person.badge.plus")
    110. }
    111. .sheet(isPresented: $showingAddPlayer) {
    112. PlayerAddView()
    113. }
    114. }
    115. } detail: {
    116. PlayerDetailView(player: selectedPlayer)
    117. }
    118. .environmentObject(playersList)
    119. }
    120. func removePlayer(at offsets: IndexSet) {
    121. playersList.players.remove(atOffsets: offsets)
    122. }
    123. }
    124. struct ContentView_Previews: PreviewProvider {
    125. static var previews: some View {
    126. ContentView()
    127. .environmentObject(PlayersList())
    128. }
    129. }
    Alles anzeigen
    SwiftUI Newbie
  • Hey und willkommen im Forum,

    ich denke du bist grundsätzlich auf dem richtigen Weg! Es fallen mir zwar ein paar Kleinigkeiten auf (wie z.B. Zeile 86: warum ist Player ein Optional? Sollte die View nicht nur angezeigt werden, wenn der Player auch existiert? oder Zeile 88/89: Force Unwrapping (also das !) sollte in 99% der Fälle vermieden werden, auch mit zugvorigem "!= nil"-Check, nutze stattdessen lieber z.B. "if let player {..." für das Unwrapping), aber ich fokussiere mich mal auf deine Kernfrage.

    Ohne das jetzt lokal getestet zu haben, würde ich folgende Vermutung anstellen: Du nutzt ein Struct für Player. Achtung, Structs in Swift sind Value Types! Das heißt, anders als Klassen (Reference Types), wird beim Übergaben einer Struct-Instanz wie z.B. dein Player keine Referenz übergeben sondern lediglich eine Kopie (z.B. Zeile 117, selectedPlayer ist bereits eine Kopie; ebenfalls der Player, den du in Zeile 139 an PlayerDetailView übergibst). Das ist der Grund, weshalb deine Split-View zwar zum Anzeigen funktioniert (du siehst ja nicht, dass es im Detail-View eine Kopie angezeigt wird), aber sobald du den Player editieren möchtest, fällt es auf. Jetzt siehst du nämlich, dass du lediglich deine Kopie änderst, diese aber keinerlei Verbindung zu deinem ursprünglichem Player in der Liste hat. Da helfen auch keine Bindings & Co, die sehen eigentlich gut aus.

    Wie kannst du das lösen? Ich sehe zwei Möglichkeiten:
    • Du änderst Player zu einer Klasse, die ObservableObject konform ist. In der PlayerDetailView sollte es dann @ObservedObject var player: Player heißen.
    • Die Variablen in der Player Klasse sollten alle @Published sein, sodass Änderungen am z.B. Namen automatisch View-Updates triggern
    Oder, falls du bei Structs bleiben möchtest (gute Übung, um den Unterschied zu lernen ;) )
    • Wann immer du aktuell einen Player übergibst, solltest du stattdessen in Zukunft z.B. lediglich die id übergeben und das Repository (sprich PlayerList) z.B. als EnvironmentObject zu Verfügung stellen. So kann jede View den aktuellen Player anhand der Id aus dem Repository ziehen und es treten weniger Redundanz-Probleme auf.
    • Beim Aktualisieren des Players wird es etwas schwieriger, da du das im Array selbst machen musst, ohne das Objekt herauszunehmen, da das bereits eine Kopie erzeugen würde. Das könnte ca so aussehen (aus dem Stegreif gecoded, könnte Fehler enthalten):

    Quellcode

    1. if let playerIndex = playerList.players.firstIndex(where: { $0.id == selectedPlayerId }) {
    2. playerList.players[playerIndex].name = newName
    3. }
    VG
  • Hallo und Danke für die beiden Antworten!
    Leider habe ich keine Mail bekommen, dass es Antworten gibt (hatte eine falsche Einstellung gewählt). Daher habe ich es jetzt zufällig entdeckt!
    Ich werde mich an beiden Vorschlägen probieren und wieder Rückmeldung geben.
    SwiftUI Newbie

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von joseb ()

  • Osxler schreibt, dass bereits mein selectedPlayer nur noch eine Kopie der Player-Instanz ist. Wenn ich Wolf folge, sollte es aber mit @Binding dennoch gehen.
    Bevor ich also mein Struct für Player in eine Class umwandle, habe ich es mit @Binding probiert.

    Der aktuelle Code für den PlayerDetailView sieht so aus (@Osxler: der Player muss doch optional sein, damit - wenn er nil ist, angezeigt wird, dass ein Spieler ausgewählt werden muss, oder?! Änderung auf if let habe ich gemacht.)

    Quellcode

    1. //PlayerDetailView
    2. import SwiftUI
    3. struct PlayerDetailView: View {
    4. @Binding var player: Player?
    5. var body: some View {
    6. if let player {
    7. Text("Hallo \(player.firstName) \(player.lastName)")
    8. // Hier soll ein Textfeld hin, welches z.B. den Vornamen des Spielers beinhaltet. Bei Änderungen im Texrfeld soll die Änderung direkt in der Auswahlliste sichtbar werden, ohne dass man über einen "Save"-Button die Änderung "aktiv" an den Spieler übergibt.
    9. }
    10. else {
    11. VStack {
    12. Image(systemName: "person.fill")
    13. Text("Select Player")
    14. }
    15. }
    16. }
    17. }
    Alles anzeigen



    Dafür erhalte ich jetzt eine Fehlermeldung im Contentview: Cannot convert value 'selectedPlayer' of type 'Player?' to expected type 'Binding<Player?>', use wrapper instead
    Die Fehlermeldung habe ich behoben indem ich ein Binding $selectedPlayer in meiner ContentView erstellt habe.

    Quellcode

    1. // ContentView
    2. // [...]
    3. } detail: {
    4. PlayerDetailView(player: selectedPlayer)
    5. }
    6. .environmentObject(playersList)
    7. // [...]
    Der Code läuft soweit gut. Jetzt müsste in den PlayerDetailView das TextField.
    Das sieht so aus:


    Quellcode

    1. //
    2. // PlayerDetailView.swift
    3. //
    4. import SwiftUI
    5. struct PlayerDetailView: View {
    6. @Binding var player: Player?
    7. var body: some View {
    8. if let player {
    9. VStack{
    10. Text("Hallo \(player.firstName) \(player.lastName)")
    11. // Hier das TextField, das einen Fehler ausgibt.
    12. TextField(
    13. "\(player.firstName)",
    14. text: $player.firstName
    15. )
    16. }
    17. }
    18. else {
    19. VStack {
    20. Image(systemName: "person.fill")
    21. Text("Select Player")
    22. }
    23. }
    24. }
    25. }
    Alles anzeigen
    Ich bekomme die Fehlermeldung in Zeile 18: Value of optional type 'Player?' must be unwrapped to refer to member 'firstName' of wrapped base type 'Player'


    Jetzt ergeben sich 2 Fragen:
    1. Wie kann ich die Fehlermeldung beheben?
    2. Wenn die Fehlermeldung behoben ist, besteht mein @Binding ja "nur" zum selectedPlayer. Und dies ist ja nur eine Kopie des tatsächlichen Player-Typs. Somit wirken sich Änderungen wiederum nicht direkt aus, oder?
    SwiftUI Newbie
  • joseb schrieb:


    Ich bekomme die Fehlermeldung in Zeile 18: Value of optional type 'Player?' must be unwrapped to refer to member 'firstName' of wrapped base type 'Playe


    Jetzt ergeben sich 2 Fragen:
    1. Wie kann ich die Fehlermeldung beheben?
    2. Wenn die Fehlermeldung behoben ist, besteht mein @Binding ja "nur" zum selectedPlayer. Und dies ist ja nur eine Kopie des tatsächlichen Player-Typs. Somit wirken sich Änderungen wiederum nicht direkt aus, oder?

    Kurz den Fehler bei Google eingegeben, schon habe ich folgende Ergebnisse zu dem Fehler...

    developer.apple.com/forums/thread/655180
    stackoverflow.com/questions/71…efer-to-member-uid-of-wra
    freecodecamp.org/news/optional-types-in-swift/

    Gerne zitiere ich da einen Freund von mir, der mir bei meinen ersten Schritten als Entwickler geholfen hat...
    "Ich helfe dir gerne, aber Googlen werde ich nicht für dich übernehmen"...

    In diesem Fall habe ich das mal für dich gemacht, aber wahrscheinlich wärst du auch mit etwas Tastatur-Dynamik am Samstag selber drauf gekommen.

    Da im übrigen eine ähnliche Fehlermeldung vor 2 Wochen schon mal kam (nicht von dir, aber von jemandem anders) hier eine kleine Empfehlung meinerseits...

    docs.swift.org/swift-book/LanguageGuide/TheBasics.html

    Da steht auch allerlei nützliches Wissen drin :)
  • ashtari schrieb:

    Gerne zitiere ich da einen Freund von mir, der mir bei meinen ersten Schritten als Entwickler geholfen hat...
    "Ich helfe dir gerne, aber Googlen werde ich nicht für dich übernehmen"...
    Ich hoffe inständig, dass jeder, bevor er hier eine Frage ins Forum stellt, Google oder auch das Handbuch gefragt hat! :) Sonst würde man sinnlos die Zeit derer verbrennen, die hier kostenlos und bereitwillig Antworten und Hilfeleistungen geben. Und mich selbst würde es auch nur bedingt weiterbringen.

    Aber als Autodidakt kommen bei mir vielleicht Fragen auf, die Ihr für so banal haltet, dass sie für euch gar nicht erst fragenswürdig sind. :D Bei mir tauchen Sie auf, weil ich manche Denkansätze oder Verhaltensweisen von Swift/SwiftUI noch nicht ganz durchdrungen habe, oder ich nicht weiß, nach was genau ich zur Problembehandlung suchen muss - außer natürlich der Fehlermeldung in Google :thumbsup: .

    Für mich stellt sich schon die grundsätzliche Frage, ob mein gewählter Ansatz überhaupt der richtige ist und ich vielleicht vergeblich nach einer Lösung suche, für die es keine gibt.
    Ist der Player als Struct im Array meiner Team class überhaupt richtig (ganz falsch ist es wohl nicht, weil es ja grundsätzlich funktioniert)? Kann ich mein @State privat var selectedPlayer über @Binding var selectedPlayer in meinem PlayerDetailView direkt verändern? Meiner Einschätzung nach schon: swiftuipropertywrappers.com/
    Oder ist dieser Ansatz schon falsch und führt deshalb zu dem Fehler?
    Vielleicht bin ich der Lösung meines Problems schon sehr nahe und ich habe nur noch einen Gedankenknoten, der mich nicht zur Lösung bringt...
    Die von ashtari zitierten Google-Ergebnisse habe ich angeschaut. Haben aber meinen Knoten noch nicht gelöst.
    SwiftUI Newbie
  • Es macht keinen Sinn, da ich ja in meinem PlayerView durch if let reinschaue, ob auch in meinem selctedPlayer etwas drin ist und der PlayerDetailView nur dann angezeigt werden kann, wenn man auch einen Player ausgewählt hat.
    Wenn ich aber das "optional" in meinem PlayerDetailView herausnehme führt das wieder zu einer Fehlermeldung in meinem PlayerView im NavigationLink, bei der Übergabe des selectedPlayer.

    Das "optional" ist also bisher nur das Ergebnis meiner Versuche einen laufenden Code zu generieren und Fehlermeldungen zu beseitigen.

    Mein momentaner Code für den PlayerView und den PlayerDetailView sieht so aus - mit der Entfernung des optionals im PlayerDetailView:

    Quellcode

    1. struct PlayerView: View {
    2. @EnvironmentObject var teamsList: TeamsList
    3. @State private var showingAddPlayer = false
    4. @State private var showingAddTeam = false
    5. @State private var visibility: NavigationSplitViewVisibility = .all
    6. @State private var searchTextTeam = ""
    7. @State private var searchTextPlayer = ""
    8. @State private var selectedTeam: Team?
    9. @State private var selectedPlayer: Player?
    10. var body: some View {
    11. NavigationSplitView(columnVisibility: $visibility) {
    12. if teamsList.teams != [] {
    13. List(selection: $selectedTeam){
    14. ForEach(filteredTeams) { team in
    15. NavigationLink(value: team){
    16. TeamRowView(team: team)
    17. }
    18. }
    19. .onDelete(perform: removeTeam)
    20. }
    21. .navigationTitle("Teams")
    22. .searchable(text: $searchTextTeam, prompt: "Search Team")
    23. .toolbar{
    24. EditButton()
    25. Button{
    26. showingAddTeam = true
    27. } label: {
    28. Image(systemName: "person.badge.plus")
    29. }
    30. .sheet(isPresented: $showingAddTeam) {
    31. TeamAddView()
    32. }
    33. }
    34. } else {
    35. VStack {
    36. Image(systemName: "person.3.fill")
    37. Text("Add a Team")
    38. }
    39. .toolbar{
    40. Button{
    41. showingAddTeam = true
    42. } label: {
    43. Image(systemName: "person.badge.plus")
    44. }
    45. .sheet(isPresented: $showingAddTeam) {
    46. TeamAddView()
    47. }
    48. }
    49. }
    50. } content: {
    51. if let selectedTeam {
    52. if selectedTeam.players != [] {
    53. List(selection: $selectedPlayer){
    54. ForEach(filteredPlayers) { player in
    55. NavigationLink(value: player){
    56. PlayerRowView(player: player)
    57. }
    58. }
    59. .onDelete(perform: removePlayer)
    60. }
    61. .navigationTitle(selectedTeam.name)
    62. .searchable(text: $searchTextPlayer, prompt: "Search Player")
    63. .toolbar{
    64. EditButton()
    65. Button{
    66. showingAddPlayer = true
    67. } label: {
    68. Image(systemName: "person.badge.plus")
    69. }
    70. .sheet(isPresented: $showingAddPlayer) {
    71. PlayerAddView(selectedTeam: $selectedTeam)
    72. }
    73. }
    74. } else {
    75. VStack {
    76. Image(systemName: "person.badge.plus")
    77. Text("Add a Player")
    78. }
    79. .toolbar{
    80. EditButton()
    81. Button{
    82. showingAddPlayer = true
    83. } label: {
    84. Image(systemName: "person.badge.plus")
    85. }
    86. .sheet(isPresented: $showingAddPlayer) {
    87. PlayerAddView(selectedTeam: $selectedTeam)
    88. }
    89. }
    90. }
    91. } else {
    92. VStack {
    93. Image(systemName: "person.3.fill")
    94. Text("Select a Team")
    95. }
    96. }
    97. } detail: {
    98. if let selectedPlayer {
    99. NavigationLink(value: selectedPlayer) {
    100. //Hier bekomme ich die Fehlermeldung
    101. PlayerDetailView(selectedPlayer: $selectedPlayer)
    102. }
    103. } else {
    104. VStack {
    105. Image(systemName: "person.fill")
    106. Text("Select Player")
    107. }
    108. }
    109. }
    110. .navigationSplitViewStyle(.balanced)
    111. }
    112. func removeTeam(at offsets: IndexSet) {
    113. teamsList.teams.remove(atOffsets: offsets)
    114. }
    115. func removePlayer(at offsets: IndexSet) {
    116. selectedTeam!.players.remove(atOffsets: offsets)
    117. if let index = teamsList.teams.firstIndex(where: {$0.id == selectedTeam!.id}) {
    118. teamsList.teams[index] = selectedTeam!
    119. }
    120. }
    121. //Suchvariable zur Aufnahme der gefilterten Teams bei Suchanfragen
    122. var filteredTeams: [Team] {
    123. if searchTextTeam.isEmpty {
    124. return teamsList.teams
    125. } else {
    126. return teamsList.teams.filter { $0.name.localizedCaseInsensitiveContains(searchTextTeam)
    127. }
    128. }
    129. }
    130. //Suchvariable zur Aufnahme der gefilterten Players bei Suchanfragen
    131. var filteredPlayers: [Player] {
    132. if searchTextPlayer.isEmpty {
    133. return selectedTeam!.players
    134. } else {
    135. return selectedTeam!.players.filter { $0.firstName.localizedCaseInsensitiveContains(searchTextPlayer) || $0.lastName.localizedCaseInsensitiveContains(searchTextPlayer)
    136. }
    137. }
    138. }
    139. }
    Alles anzeigen


    Quellcode

    1. struct PlayerDetailView: View {
    2. @EnvironmentObject var teamsList: TeamsList
    3. @Binding var selectedPlayer: Player
    4. var body: some View {
    5. VStack{
    6. Text("Hello \(selectedPlayer.firstName) \(selectedPlayer.lastName)")
    7. TextField(selectedPlayer.firstName, text: $selectedPlayer.firstName)
    8. }
    9. }
    10. }
    Alles anzeigen

    Im PlayerView erhalte ich in Zeile 102 aber dann den Fehler: Cannot convert value of type 'Binding<Player?>' to expected argument type 'Binding<Player>'

    Hier beschwert er sich jetzt ja, dass er einen optionalen Player (in diesem Fall mein @State private var selectedPlayer: Player?) an einen nicht mehr optionalen Player im PlayerDetailView binden soll. So interpretiere ich zumindest die Meldung.

    Damit kann ich also immer noch nicht die Eingaben ins TexField im PlayerDateilView an den selectedPlayer übergeben und damit unmittelbar bei der Eingabe von Text auch Änderungen im PlayerRowView (also der Liste der Player) sehen.


    Meine Grundidee ist immer noch, dass ich das TextField im PlayerDetailView auf inaktiv/disabled setze. Wenn ich dann auf einen Button klicke, wird das TextField aktiviert und ich kann Änderungen vornehmen (Code dafür habe ich noch nicht eingebunden).

    Vielleicht geht das mit meinem Ansatz nicht und ich muss einen ganz eigenständigen "EditView" machen?!
    SwiftUI Newbie
  • Hallo Babelfisch, das hat schon mal geklappt - vielen Dank. Der Code läuft ohne Fehler durch.
    Jetzt wird aber auch erkennbar, dass selectedPlayer bereites eine Kopie meiner Player ist, wie Osxer schon geschrieben hat.

    Osxer schrieb:

    Du nutzt ein Struct für Player. Achtung, Structs in Swift sind Value Types! Das heißt, anders als Klassen (Reference Types), wird beim Übergaben einer Struct-Instanz wie z.B. dein Player keine Referenz übergeben sondern lediglich eine Kopie (z.B. Zeile 117, selectedPlayer ist bereits eine Kopie; ebenfalls der Player, den du in Zeile 139 an PlayerDetailView übergibst). Das ist der Grund, weshalb deine Split-View zwar zum Anzeigen funktioniert (du siehst ja nicht, dass es im Detail-View eine Kopie angezeigt wird), aber sobald du den Player editieren möchtest, fällt es auf. Jetzt siehst du nämlich, dass du lediglich deine Kopie änderst, diese aber keinerlei Verbindung zu deinem ursprünglichem Player in der Liste hat. Da helfen auch keine Bindings & Co, die sehen eigentlich gut aus.
    Denn wenn ich Text in das Textfeld eingebe, ändert er die Anzeige von Text("Hello \(selectedPlayer.firstName) \(selectedPlayer.lastName)"), gibt das aber nicht weiter an den originalen Player. Denn wenn ich einen anderen Player in der Liste auswähle und dann zurückkehre, sind die Änderungen wieder weg. Das @Binding ist wohl in der Lage auch in structs zu schreiben. Aber in meinem Code schreibt es in selectedPlayer und damit in eine Kopie meines Player-structs.

    Somit sind meine weiteren Hausaufgaben, bzw. Lösungsansätze:
    1. Im PlayerDetailView über einen Button eine Art "save"-Funktion einzubauen, welche die Änderungen an den richtigen Player übergibt, so wie von Osxer vorgeschlagen, wobei man dann auf @Binding verzichten kann

      Quellcode

      1. if let playerIndex = playerList.players.firstIndex(where: { $0.id == selectedPlayerId }) {
      2. playerList.players[playerIndex].name = newName
      3. }
    2. ODER Aus meinem Player-struct eine Player-class machen, um zu gewährleisten, dass ich auch den Player direkt anfasse und nicht eine Kopie davon
    Mal sehen, was meine abendlichen Versuche für Ergebnisse bringen...
    SwiftUI Newbie
  • Ohne mir jetzt deinen ganzen Code genau angesehen zu haben wäre mein Ansatz, einfach statt den Player (wegen Struct als Kopie) an die Views durchzureichen, besser nur die Player-ID weiterzugeben und über die ID dann im EnvironmentObject playersList immer den Player direkt zu nutzen.
    So Long, and Thanks for All the Fish.