DavidODW
DavidODW

Reputation: 417

iOS - Data persist once into Core Data

I'm trying to save a bunch of data into core data. I could manage to save all the data into core data but it make no sense to have duplicate data inside core data because the function will be execute once on every build of the project. The approach that I am thinking now is empty the entity's record before I am adding new record to it. Just want to know is that got another way around to make sure that the data only persist once?

func persistCurrencyData() {
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate

    let managedContext = appDelegate.managedObjectContext

    let currencyEntity = NSEntityDescription.entityForName("Currency", inManagedObjectContext: managedContext)


    let countryEntity = NSEntityDescription.entityForName("Country", inManagedObjectContext: managedContext)

    for currency in currencies {
      let currencyObject = CurrencyCore(entity: currencyEntity!, insertIntoManagedObjectContext: managedContext)

      currencyObject.setValue(currency.code, forKeyPath: "code")
      currencyObject.setValue(currency.name, forKeyPath: "name")

      for country in currency.country! {
        let countryObject = CountryCore(entity: countryEntity!, insertIntoManagedObjectContext: managedContext)

        countryObject.setValue(country.name, forKeyPath: "name")
        countryObject.setValue(country.code, forKeyPath: "code")
        countryObject.setValue(country.continent, forKeyPath: "continent")
        countryObject.setValue(country.continentCode, forKeyPath: "continentCode")

        countryObject.currency = currencyObject
      }
    }

    do {
      try managedContext.save()
    } catch let error as NSError  {
      print("Could not save \(error), \(error.userInfo)")
    }
}

Update:

Thanks to @Wain for giving me the idea. Basically what I done to solve the saving of duplicate data in core data is I included an GUID in my JSON file. Every time the code read the JSON file, it will save GUID into NSUserDefault and save data into core data. When it wants to read JSON file again in the next build, it will check whether the GUID is same as previous saved GUID. If it is different, the code will read the JSON file and repeat the process above. If not, it will proceed and ignore it.

func requestCurrenciesData() {
    getCurrenciesDataFromFileWithSuccess { (data) -> Void in
      var json: [String: AnyObject]

      do {
        json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as! [String: AnyObject]

        guard let currencyData = CurrencyData(json: json) else {
          print("Error initializing object")
          return
        }

        self.currencies = currencyData.currency!

        // Checking the JSON's id is same as previous read
        let defaults = NSUserDefaults.standardUserDefaults()
        if let id = defaults.stringForKey("id")
        {
          if id == currencyData.id {
            let notification = NSNotification(name: "CurrenciesDataUpdate", object: nil)
            NSNotificationCenter.defaultCenter().postNotification(notification)

            return
          }
        }

        self.persistCurrencyDataForId(currencyData.id)

        let notification = NSNotification(name: "CurrenciesDataUpdate", object: nil)
        NSNotificationCenter.defaultCenter().postNotification(notification)
      } catch {
        print(error)
        return
      }
   }
}

func persistCurrencyDataForId(id: String) {
    // Save the new JSON's id into NSUserDefaults
    let defaults = NSUserDefaults.standardUserDefaults()
    defaults.setObject(id, forKey: "id")

    // Delete all the records in existing table
    deleteRecordsFromEntity("Country")
    deleteRecordsFromEntity("Currency")

    // Insert the new records
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext

    let currencyEntity = NSEntityDescription.entityForName("Currency", inManagedObjectContext: managedContext)
    let countryEntity = NSEntityDescription.entityForName("Country", inManagedObjectContext: managedContext)

    for currency in currencies {
      let currencyObject = CurrencyCore(entity: currencyEntity!, insertIntoManagedObjectContext: managedContext)

      currencyObject.setValue(currency.code, forKeyPath: "code")
      currencyObject.setValue(currency.name, forKeyPath: "name")

      for country in currency.country! {
        let countryObject = CountryCore(entity: countryEntity!, insertIntoManagedObjectContext: managedContext)

        countryObject.setValue(country.name, forKeyPath: "name")
        countryObject.setValue(country.code, forKeyPath: "code")
        countryObject.setValue(country.continent, forKeyPath: "continent")
        countryObject.setValue(country.continentCode, forKeyPath: "continentCode")

        countryObject.currency = currencyObject
      }
    }

    do {
      try managedContext.save()
    } catch let error as NSError  {
      print("Could not save \(error), \(error.userInfo)")
    }
  }

func deleteRecordsFromEntity(entityName: String) {
    let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
    let managedContext = appDelegate.managedObjectContext
    let coordinator = appDelegate.persistentStoreCoordinator

    let fetchRequest = NSFetchRequest(entityName: entityName)
    let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetchRequest)

    do {
      try coordinator.executeRequest(deleteRequest, withContext: managedContext)
    } catch let error as NSError {
      print(error)
    }
 }

Upvotes: 4

Views: 97

Answers (1)

Wain
Wain

Reputation: 119021

In general you can say 'if i have any currency entries in the data store, don't add more'. That could be done by adding a flag to use defaults or something like that when you do the first import, but a better option is to check the data store to see if it has any currency entries. To do this create a fetch request for currencyEntity and use countForFetchRequest:error: before you carry on with for currency in currencies {. If the count is greater than zero then you should return instead of processing the loop.

To be more efficient this check should actually be before you download and process the JSON...

Upvotes: 1

Related Questions