-1

I am pretty new in the Core Data and trying to save an array made of custom object but there is small problem: I don't know how to do it the right way. The application retrieves data from the network and writes it to the Core Data database. It contains several arrays and objects that are custom objects. There is no problem with writing strings, ints etc. But how do I save a list of custom objects? The objects used to get data from the web are a bit different to the ones used to work with Core Data, so I can't just assign them. Of course, this can be done in the next loop, but isn't there anything better? I am completely new to Core Data and I am looking for the best solutions for slightly more complex operations. Is Core Data worth using for complex operations?

CoreDataService:

protocol CoreDataServiceProtocol {

func saveCountries(countries: [Country])
func fetchCountries() -> [CountryCoreData]
}

final class CoreDataService : CoreDataServiceProtocol {

private var persistentContainer: NSPersistentContainer = {
    let persistentContainer = NSPersistentContainer(name: "CountriesAPI")
    persistentContainer.loadPersistentStores { _, error in
        print(error?.localizedDescription ?? "")
    }
    return persistentContainer
}()

var viewContext: NSManagedObjectContext {
    return persistentContainer.viewContext
}

func saveCountries(countries: [Country]) {
    for country in countries {
        let newCountry = CountryCoreData(context: viewContext)
        
        for currency in country.currencies {
            
            newCountry.addToCurrencyCoreData(currency)
        }
        //Below, I can easily create a new object that I want to assign as a parent property
        var translation = TranslationCoreData(context: viewContext)
        translation.br = country.translations?.br
        newCountry.addToTranslationCoreData(translation)
        
        //If there is no relationship between the models this way is pretty nice, but in my case there are several relationships
        newCountry.setValue(country.alpha2Code, forKey: "alpha2Code")
        newCountry.setValue(country.alpha3Code, forKey: "alpha3Code")
        newCountry.setValue(country.altSpellings, forKey: "altSpellings")
        newCountry.setValue(country.area, forKey: "area")
        newCountry.setValue(country.borders, forKey: "borders")
        newCountry.setValue(country.callingCodes, forKey: "callingCodes")
        newCountry.setValue(country.capital, forKey: "capital")
        newCountry.setValue(country.cioc, forKey: "cioc")
       // newCountry.setValue(country.currencies, forKey: "currencies")
        newCountry.setValue(country.demonym, forKey: "demonym")
        newCountry.setValue(country.flag, forKey: "flag")
        newCountry.setValue(country.gini, forKey: "gini")
        //newCountry.setValue(country.id, forKey: "id")
       // newCountry.setValue(country.languages, forKey: "languages")
        newCountry.setValue(country.name, forKey: "name")
        newCountry.setValue(country.nativeName, forKey: "nativeName")
        newCountry.setValue(country.numericCode, forKey: "numericCode")
        newCountry.setValue(country.population, forKey: "population")
        newCountry.setValue(country.region, forKey: "region")
       // newCountry.setValue(country.regionalBlocs, forKey: "regionalBlocs")
        newCountry.setValue(country.subregion, forKey: "subregion")
        newCountry.setValue(country.timezones, forKey: "timezones")
        newCountry.setValue(country.topLevelDomain, forKey: "topLevelDomain")
       // newCountry.setValue(country.translations, forKey: "translations")

    }
    do {
        try viewContext.save()
        print("Success")
    } catch {
        print("Error saving: \(error.localizedDescription)")
    }
}

Model generated by CoreDataxcdatamodel - CountryCoreData:

import Foundation
import CoreData


extension CountryCoreData {

@nonobjc public class func fetchRequest() -> NSFetchRequest<CountryCoreData> {
    return NSFetchRequest<CountryCoreData>(entityName: "CountryCoreData")
}

@NSManaged public var alpha2Code: String?
@NSManaged public var alpha3Code: String?
@NSManaged public var altSpellings: [String]?
@NSManaged public var area: Double
@NSManaged public var borders: [String]?
@NSManaged public var callingCodes: [String]?
@NSManaged public var capital: String?
@NSManaged public var cioc: String?
@NSManaged public var currencies: [CurrencyCoreData]?
@NSManaged public var demonym: String?
@NSManaged public var flag: String?
@NSManaged public var gini: Double
@NSManaged public var id: UUID?
@NSManaged public var languages: [LanguageCoreData]?
@NSManaged public var name: String?
@NSManaged public var nativeName: String?
@NSManaged public var numericCode: String?
@NSManaged public var population: Int16
@NSManaged public var region: String?
@NSManaged public var regionalBlocks: [RegionalBlockCoreData]?
@NSManaged public var subregion: String?
@NSManaged public var timezones: [String]?
@NSManaged public var topLevelDomain: [String]?
@NSManaged public var translations: [TranslationCoreData]?
@NSManaged public var currencyCoreData: NSSet?
@NSManaged public var languageCoreData: NSSet?
@NSManaged public var regionalBlockCoreData: NSSet?
@NSManaged public var translationCoreData: NSSet?

}

// MARK: Generated accessors for currencyCoreData
extension CountryCoreData {

@objc(addCurrencyCoreDataObject:)
@NSManaged public func addToCurrencyCoreData(_ value: CurrencyCoreData)

@objc(removeCurrencyCoreDataObject:)
@NSManaged public func removeFromCurrencyCoreData(_ value: CurrencyCoreData)

@objc(addCurrencyCoreData:)
@NSManaged public func addToCurrencyCoreData(_ values: NSSet)

@objc(removeCurrencyCoreData:)
@NSManaged public func removeFromCurrencyCoreData(_ values: NSSet)

}

// MARK: Generated accessors for languageCoreData
extension CountryCoreData {

@objc(addLanguageCoreDataObject:)
@NSManaged public func addToLanguageCoreData(_ value: LanguageCoreData)

@objc(removeLanguageCoreDataObject:)
@NSManaged public func removeFromLanguageCoreData(_ value: LanguageCoreData)

@objc(addLanguageCoreData:)
@NSManaged public func addToLanguageCoreData(_ values: NSSet)

@objc(removeLanguageCoreData:)
@NSManaged public func removeFromLanguageCoreData(_ values: NSSet)

}

// MARK: Generated accessors for regionalBlockCoreData
extension CountryCoreData {

@objc(addRegionalBlockCoreDataObject:)
@NSManaged public func addToRegionalBlockCoreData(_ value: RegionalBlockCoreData)

@objc(removeRegionalBlockCoreDataObject:)
@NSManaged public func removeFromRegionalBlockCoreData(_ value:   RegionalBlockCoreData)

@objc(addRegionalBlockCoreData:)
@NSManaged public func addToRegionalBlockCoreData(_ values: NSSet)

@objc(removeRegionalBlockCoreData:)
@NSManaged public func removeFromRegionalBlockCoreData(_ values: NSSet)

}

// MARK: Generated accessors for translationCoreData
extension CountryCoreData {

@objc(addTranslationCoreDataObject:)
@NSManaged public func addToTranslationCoreData(_ value: TranslationCoreData)

@objc(removeTranslationCoreDataObject:)
@NSManaged public func removeFromTranslationCoreData(_ value: TranslationCoreData)

@objc(addTranslationCoreData:)
@NSManaged public func addToTranslationCoreData(_ values: NSSet)

@objc(removeTranslationCoreData:)
@NSManaged public func removeFromTranslationCoreData(_ values: NSSet)

}

extension CountryCoreData : Identifiable {

}
beginner992
  • 659
  • 1
  • 9
  • 28
  • It’s not really clear what exactly you are asking about when you say “list of custom objects”, could you clarify? And why do you have array properties in your managed model and also similar relationships like `currencies` and `currencyCoreData`, is there a reason for this? And what are “complex operations”? – Joakim Danielson Sep 19 '21 at 14:16
  • It's not clear What's your entity name and also you need to save array of your entity name? What is TranslationCoreData? – Yogesh Patel Sep 19 '21 at 15:49
  • To most efficient way with regard to performance is to *translate* the custom objects into Core Data entities and use relationships. – vadian Sep 19 '21 at 16:10

1 Answers1

1

In my opinion first change these things

Instead of this

newCountry.setValue(country.alpha2Code, forKey: "alpha2Code")

add this line

newCountry.alpha2Code = country.alpha2Code

Do this way on your Save countries function

 func saveCountries(countries: [Country]) {
       for country in countries {
            let newCountry = CountryCoreData(context: viewContext)
            newCountry.alpha2Code = country.alpha2Code//add this line         
        }
        saveContext()
    }

Create ViewContext function so you can reuse this!

func saveContext(){
 do {
        try viewContext.save()
        print("Success")
    } catch {
        print("Error saving: \(error.localizedDescription)")
    }
}

Using Transformable type you can save array directly in the CoreData without for loop https://stackoverflow.com/a/29827564/8201581

Yogesh Patel
  • 1,893
  • 1
  • 20
  • 55
  • @beginner992 Is it working? If Yes then please accept the answer so it will helpful for other too. Let me know if you have any question regarding this! – Yogesh Patel Sep 20 '21 at 08:52
  • I am very sorry for very late answer. Your solution works of course, but Transformable type works only if we don't use custom type. Thank you so much for your help! – beginner992 Sep 23 '21 at 18:27