Learn Courses My Dashboard

Having Trouble Saving Data

I am really having a hard time using CoreData to save my favourites when the app terminates and I relaunch it my favourites are gone. I have some code in my appDelegate that should work but it does not. What should I do?

func applicationWillTerminate(_ application: UIApplication) {
       // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
       // Saves changes in the application's managed object context before the application terminates.
    PersistenceService.saveContext()
   }

Welcome to the community!

What’s the code for your PersistenceService??

This is the complete code I have for it.

import Foundation
import CoreData

class PersistenceService {
    
    private init() {}
        
        static var context: NSManagedObjectContext {
            return persistentContainer.viewContext
        }

// MARK: CoreData
static var persistentContainer: NSPersistentContainer = {
    /*
     The persistent container for the application. This implementation
     creates and returns a container, having loaded the store for the
     application to it. This property is optional since there are legitimate
     error conditions that could cause the creation of the store to fail.
    */
    let container = NSPersistentContainer(name: "playerModel")
    container.loadPersistentStores(completionHandler: { (storeDescription, error) in
        if let error = error as NSError? {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
             
            /*
             Typical reasons for an error here include:
             * The parent directory does not exist, cannot be created, or disallows writing.
             * The persistent store is not accessible, due to permissions or data protection when the device is locked.
             * The device is out of space.
             * The store could not be migrated to the current model version.
             Check the error message to determine what the actual problem was.
             */
            fatalError("Unresolved error \(error), \(error.userInfo)")
        }
    })
    return container
}()

static func saveContext () {
    let context = persistentContainer.viewContext
    if context.hasChanges {
        do {
            try context.save()
        } catch {
            // Replace this implementation with code to handle the error appropriately.
            // fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nserror = error as NSError
            fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
        }
    }
}
}

I have given the complete code and am not sure what else to do.

Where are you ever changing your favorites? Just using basic CRUD applications, do you have that working?

Creating favorites, reading, updating, deleting.

The app delegate function that you have is only ever needed for when the user forces closes an app but you may be in the middle of a process, like actively connected to a database, in that function is where you’d close the connection.

I don’t have a database I just have a TableViewController with all my favourites which are my cells. I just want to be able to save them when the app gets terminated and the user has to restart it.

If you are using core data you need to set up a schema. And it is a database.

I’d suggest going through this tutorial series and then modifying it for your own app

I already set it up it just does not seem to work when I save it locally after terminating the app.

You usually only ever need this function, applicationWillTerminate, when saving data to a server, not to core data.

Do you have code in place to do all the other CRUD functions and those work?

Okay I rewatched the video and I see this code maybe this should work.

do {
try self.context.save()
} catch {

}

Yes that is possible, but this entire function would only ever be needed if you’re changing the data and not using saveContext immediately afterwards (which you shouldn’t be doing)

I’m not changing the data I am just trying to save my object which is this

var currentFav: CurrentPlayers?

You should be saving the object at any point where you want to edit the data.

Because I’m then confused you’re running this when the app terminated and saying that the data isn’t saving, which would mean you aren’t saving it at the same point you’re changing the data.

You wouldn’t really need this function in the app will terminate, cause the data would’ve already been saved?

By saved I mean to have my object remain when the app closes and then opens again because if I favourite one player (I will see it on my favourites menu on the app) but if I close the app and open it again I won’t see it on the favourites menu. I need to do something in the code to achieve that functionality.

At that point when you favorite a player, you should be calling saveContext

Not only calling it when the app is terminated

I’m still confused because I don’t know where exactly to put my saveContext I have it both in my notification selector and my add to favourites button but it does not work.

@objc func handleFavNotification(notification:Notification){
            if let theFav = notification.object as? CurrentPlayers {
                PersistenceService.saveContext()
                self.item = theFav
            }
        }

    @IBAction func addToFav(_ sender: Any) {
               let alert = UIAlertController(title: "Favourite Added 💙", message: "\(name.text ?? "") is added to favourites", preferredStyle: .alert)
               alert.addAction(UIAlertAction(
                    title: "OK",
                    style: UIAlertAction.Style.default)
               { [self] _ in
                        FavouriteManager.shared.add(item)
                        PersistenceService.saveContext()
                    })
               self.present(alert, animated: true, completion: nil)
               print("Favourite button Pressed")
           }

I would recommend watching the CoreData video I linked earlier

What is this doing?

Wherever you change the model (changing properties in your array) like changing the isFavorite property of an object, it’s at that point you should be calling save context

I watched the video but it’s a different situation because he is creating a Person object to be saved, I am calling data from an API and saving. I have a class that posts my notification (will show code below). The thing about my model is I am not really changing the properties of my objects I don’t have a isFavourite property.

class FavouriteManager {
    
    
    static let shared = FavouriteManager()
    
    var favSet: OrderedSet<CurrentPlayers> = OrderedSet()
    
    func add(_ player: CurrentPlayers) {
        favSet.append(player)
        NotificationCenter.default.post(
            name: .passFavNotification,
            object: player
        )
    }
}

Okay so you have an OrderedSet of players and you’re just adding players to that.

Why are you posting notifications?

After adding the player to favSet you should be calling save context in the next line

I do I am using notifications because it was the only way to transfer data forward using a button with no segues. I call saveContext after I append the player in my set but that does not work.

func add(_ player: CurrentPlayers) {
    favSet.append(player)
    PersistenceService.saveContext()
    NotificationCenter.default.post(
        name: .passFavNotification,
        object: player
    )
}