'Can't save my objects with CoreData - SwiftUI

I have an application which should let me calculate standings of a game with my friends manually. Now I also want to save that Game to CoreData for training reasons and I don't know how I could debug my code easily.

In my CoreData File I have Standing Class which is a SubClass of MultiplayerGame and that is a SubClass of my Class Game:

Game -> MultiplayerGame -> Standing

So now to my Data Model:

My Standing Class is empty so it has no attributes - but it helps me to name it as a Standing Standing Class

So my MultiplayerGame Class should have a name of the game and an Array of the Players Multiplayer Class

This is my Game Class so that the game have an ID, a Data and an Int which says how much rounds were played Game Class

This is the Player Class - playerColor stores a Color instance with a Transformer Player Class

So now to my Code:

At first my View where I create my Standing

struct CreateStandingView: View {
    
    //Managed Object Context to store data
    @Environment(\.managedObjectContext) private var moc
    
    //Create Instance of my Standing as a MultiplayerGame
    @State private var standingGame : MultiplayerGame = Standing()
    
    //Variables for my Standing instance
    @State private var gameName : String = ""
    
    //Variables for Player
    @State private var newPlayerName : String = ""
    @State private var newPlayerColor : Color = Color.random

    //Empty Player Array for my game - it is filled here in the View
    @State private var newPlayers : [Player] = []
    
    //For my NavigationLink
    @State private var selectPlay: Int? = nil
    
    var body: some View {
        
            VStack{
                
                List{
                    Section(header: Text("Settings")){
                        TextField("Enter Game Name", text: $gameName)
                            .font(.title3.bold())
                    }
                    
                    //Player management
                    Section(header: Text("Players")){
                        
                        let textWidth : CGFloat = UIScreen.main.bounds.width - 120
                        let rowHeight : CGFloat = 30
                        
                        ForEach(newPlayers, id: \.self){ player in
                            
                            Text("\(player.playerName!)")
                                .bold()
                                .frame(width: textWidth, height: rowHeight, alignment: .leading)
                                .lineLimit(1)
                            
                        }
                        
                        //Delete player by swiping on the name
                        .onDelete(perform: {
                            indexSet in
                            newPlayers.remove(atOffsets: indexSet)
                        })
                        
                        HStack{
                        
                            TextField("Add Player Name", text: $newPlayerName)
                            
                            //Add button
                            Button(action: {
                                
                                //Create MOC object for player
                                let player : Player = Player(context: self.moc)
                                player.playerName = newPlayerName
                                
                                //Add Player to Array
                                newPlayers.append(
                                    player
                                )
                                
                                //Set value to default
                                newPlayerName = ""
                            }) {
                                Image(systemName: "plus.circle.fill")
                            }
                            .frame(width: 10, height: 10, alignment: .center)
                            .disabled(newPlayerName.isEmpty)
                        }
                    }
                }.listStyle(InsetGroupedListStyle())
                
                //Variable for disable the button
                let isDisabled : Bool = (gameName.isEmpty || newPlayers.isEmpty)
                
                //NavigationLink to EditView
                NavigationLink(destination: StandingEditStandingGameView(game: $standingGame), tag: 1, selection: $selectPlay){}
                
                //Button navigates to the next View and stores the data in the StandingGame - Instance
                Button(action: {
                    standingGame = Standing(context: moc)
                    standingGame.gameID = UUID()
                    standingGame.date = Date.now
                    standingGame.players = NSOrderedSet(array: newPlayers)
                    standingGame.name = gameName
                    standingGame.gameRounds = 0
                    
                    //Variable for Navigation Link
                    self.selectPlay = 1
                }, label: {
                    Text("Continue")
                }).disabled(isDisabled)

            }.navigationBarTitle("Create Standing")
    }
}

And now my View, where I can calculate the Scores and Quit the Game (quitting should save the object to my CoreData, but it always prints "Standing couldn't be saved")

struct StandingEditStandingGameView: View {
    
    //Managed Object Context Variables
    @Environment(\.managedObjectContext) var moc
    
    //Our Binding for the Standing game from above
    @Binding var game : MultiplayerGame
    
    //Variable to add/substract the Points
    @State private var addingPoints : Bool = true
    @State private var invokeFunction : Bool = false
    
    //Array of my Players
    private var players : [Player] {
        return game.players?.array as! [Player]
    }
    
    //Variable for my NavigationLink
    @State private var quitGame: Int? = nil
    
    var body: some View {
  
            VStack{
                
                List{
                    ForEach(players, id: \.self){ player in
                        //Here is the Logic for each View - but Standing game isn't mutated here
                        StandingNameDetailView(invokeFunction: $invokeFunction, addingPoints: addingPoints, player: player)
                    }
                }
                
                Button(action: {
                    invokeFunction.toggle()
                    game.gameRounds += 1
                }, label: {
                    Text("Calculate")
                })
                
            }
            .navigationTitle(game.name ?? "Scores")
            .navigationBarBackButtonHidden(true)
            .toolbar{
                ToolbarItem(placement: .navigationBarTrailing){
                    Button("Quit Game"){
                        do{
                            //Here I try to save my data - but it always prints the "catch" method
                            try moc.save()
                            print("Standing Game was saved")
                        } catch {
                            print("Standing Game couldn't be saved")
                        }
                        
                        //Variable for NavigationLink
                        quitGame = 1
                    }
                }
            }
            
            //NavigationLink for quitting the game
            NavigationLink(destination: StartView(), tag: 1, selection: $quitGame){}
    }
}

So thank you for reading this problem - I hope I can get some help and learn for my future projects... Thank you!



Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source