mres
mres

Reputation: 143

Strange Core Data behaviour (duplicating entries)

I have a small game and I want to store a number that represents the last level that user has unlocked. So I've got a class to save and load core data.

First I declare needed objects to handle core data (I took them from a tutorial)

    override init() {
        super.init()

        appDelegate = UIApplication.sharedApplication().delegate as AppDelegate
        managedContext = appDelegate.managedObjectContext!
        entity = NSEntityDescription.entityForName("Data", inManagedObjectContext: managedContext)
        data = NSManagedObject(entity: entity!, insertIntoManagedObjectContext: managedContext)

This is my save method

    func saveData() {
        data.setValue(lastUnlockedLevel, forKey: "lastUnlockedLevel")

        var error: NSError?
        if !managedContext.save(&error) {
            println("Could not save \(error), \(error?.userInfo)")
        }
    }

And this is my load method

func loadData() {
    let fetchRequest = NSFetchRequest(entityName: "Data")
    fetchRequest.returnsObjectsAsFaults = false

    var error: NSError?
    let fetchedResults = managedContext.executeFetchRequest(fetchRequest, error: &error) as [NSManagedObject]?

    if let results = fetchedResults {
        if results.count == 0 {
            createInitialData()
        } else if results.count > 0 {
            lastUnlockedLevel = results[0].valueForKey("lastUnlockedLevel") as Int
        }
    } else {
        println("Could not fetch \(error), \(error?.userInfo)")
    }
}

I am a newbie, so I might get the idea wrong. Once my app is loaded - I check if there is core data present. If not - I set the lastUnlockedLevel variable to 1. When I unlock a level, I increment my var and save it to apps storage.

When I load app one again I trace my results array and see something like this:

[<NSManagedObject: 0x14602790> (entity: Data; id: 0x14602650 <x-coredata://B994407F-5A33-446F-BB13-758F1190A45A/Data/p1> ; data: {
lastUnlockedLevel = 2;}),
<NSManagedObject: 0x14607770> (entity: Data; id: 0x14602670 <x-coredata://B994407F-5A33-446F-BB13-758F1190A45A/Data/p3> ; data: {
lastUnlockedLevel = 0;}),
<NSManagedObject: 0x1460ae20> (entity: Data; id: 0x1460ae50 <x-coredata:///Data/t3EEBBE5F-DF13-4C34-AE59-96AEE72DF0A52> ; data: {
lastUnlockedLevel = 0;}), 
<NSManagedObject: 0x14607740> (entity: Data; id: 0x14602660 <x-coredata://B994407F-5A33-446F-BB13-758F1190A45A/Data/p2> ; data: {
lastUnlockedLevel = 0;

Several entries for the same database field. I understand there should be only one entry? What's more confusing, I never save data when my lastUnlockedLevel is 0. What do I do wrong? })]

Upvotes: 1

Views: 296

Answers (1)

Matteo Piombo
Matteo Piombo

Reputation: 6726

I encourage you to use a much more simpler solution. Use NSUserDefaults, this class was specifically introduced for this kind of uses.

In a global part of you code, you could add this:

private let lastUnlockedLevelKey = "LastUnlockedLevel"
public var lastUnlockedLevel: Int {
get {
    let userDefaults = NSUserDefaults.standardUserDefaults()
    let theLevel = userDefaults.integerForKey(lastUnlockedLevelKey)

    return theLevel > 0 ? theLevel : 1
}
set {
    let userDefaults = NSUserDefaults.standardUserDefaults()
    userDefaults.setInteger(newValue, forKey: lastUnlockedLevelKey)
    userDefaults.synchronize()
}
}

For example you can put this at the beginning of you AppDelegate.swift (outside the class definition).

Than from wherever in you code you can use lastUnlockedLevel as a normal variable. It will be saved in the standard user defaults every time you set it.

Upvotes: 3

Related Questions