5

I have an array of type [User] and I want to save it in Core Data and later display it in a Table View. Here are my functions for saving and retrieving the data:

func saveUserData(_ users: [User]) {
    let context = appDelegate.persistentContainer.viewContext
    let newUser = NSEntityDescription.insertNewObject(forEntityName: "Users", into: context)
    for user in users {
        newUser.setValue(user.id, forKey: "id")
        newUser.setValue(user.name, forKey: "name")
        newUser.setValue(user.email, forKey: "email")
        newUser.setValue(user.phone, forKey: "phone")
        newUser.setValue(user.website, forKey: "website")
        newUser.setValue(user.city, forKey: "city")
        newUser.setValue(user.lat, forKey: "lat")
        newUser.setValue(user.long, forKey: "long")
    }
    do {
        try context.save()
        print("Success")
    } catch {
        print("Error saving: \(error)")
    }
}

func retrieveSavedUsers() -> [User]? {
    let context = appDelegate.persistentContainer.viewContext
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "Users")
    request.returnsObjectsAsFaults = false
    var retrievedUsers: [User] = []
    do {
        let results = try context.fetch(request)
        if !results.isEmpty {
            for result in results as! [NSManagedObject] {
                guard let id = result.value(forKey: "id") as? Int else { return nil }
                guard let name = result.value(forKey: "name") as? String else { return nil }
                guard let email = result.value(forKey: "email") as? String else { return nil }
                guard let phone = result.value(forKey: "phone") as? String else { return nil }
                guard let website = result.value(forKey: "website") as? String else { return nil }
                guard let city = result.value(forKey: "city") as? String else { return nil }
                guard let lat = result.value(forKey: "lat") as? String else { return nil }
                guard let long = result.value(forKey: "long") as? String else { return nil }
                let user = User(with: id, name: name, email: email, phone: phone, website: website, city: city, lat: lat, long: long)
                retrievedUsers.append(user)
            }
        }
    } catch {
        print("Error retrieving: \(error)")
    }
    return retrievedUsers
}

Retrieving works just fine, but the problem is it only saves the last object of type User in Core Data. It seems that when I am iterating trough users when I am saving them, each iteration overwrites the user object instead saving a new one. Any idea how to fix this or is there any better way of saving an array of custom objects into Core Data?

2
  • Nice answer,I wanted to ask, the type "User" is declared as a normal class or as a NSManagedObject? Commented Apr 1, 2020 at 10:24
  • 1
    @bellaGU User is defined like this class User: Mappable Commented Apr 2, 2020 at 8:18

1 Answer 1

13

You are only creating one user entity, then just writing over it each time. The problem is that just before you loop through your users array, you create a new entity. You should be doing this for every user in the array. It's a very easy fix, just swap two lines. See below for the correct code:

func saveUserData(_ users: [User]) {
    let context = appDelegate.persistentContainer.viewContext
    for user in users {
        let newUser = NSEntityDescription.insertNewObject(forEntityName: "Users", into: context)
        newUser.setValue(user.id, forKey: "id")
        newUser.setValue(user.name, forKey: "name")
        newUser.setValue(user.email, forKey: "email")
        newUser.setValue(user.phone, forKey: "phone")
        newUser.setValue(user.website, forKey: "website")
        newUser.setValue(user.city, forKey: "city")
        newUser.setValue(user.lat, forKey: "lat")
        newUser.setValue(user.long, forKey: "long")
    }
    do {
        try context.save()
        print("Success")
    } catch {
        print("Error saving: \(error)")
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

I'm doing a similar thing just that I also have core data constraints in place. On adding entities in a loop core data crashes with a message : "Unique constraint Violation: "

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.