ICL1901
ICL1901

Reputation: 7778

Inserting data into a Core Data model is unacceptably slow

I need to be able to import over 100,000 records on a weekly basis. The data is coming from a web service as a CSV file. Downloading it is fast, as is massaging it into a usable form. However, adding the records to the model works but is unacceptably slow -almost an hour!

I realize I'm saving after each record. There must be a better way to do this.

Please advise or point me to another answer. Here is my working code. Many thanks.

func loadDataBase() {

    for i in 1..<objectArray.count - 1 {

        let item: [String] = objectArray[i]


        s_stop_id = Int(item[0])
        s_stop_code = Int(item[1])
        s_stop_name = item[2]

        let mainDelegate = UIApplication.shared.delegate as! AppDelegate
        let context = mainDelegate.persistentContainer.viewContext

        let newResource = NSEntityDescription.insertNewObject(forEntityName: stopEntity, into: context)

        newResource.setValue(s_stop_id, forKey: "stop_id")
        newResource.setValue(s_stop_name, forKey: "stop_name")
        newResource.setValue(s_stop_code, forKey: "stop_code")


        do {
            try context.save()

        } catch let error as NSError  {
            print("Error While Saving Data: \(error.userInfo)")
        }
    }

I'm showing some usage information. I appear to be using 100% CPU. Is it feasible to run this process in the background? Then timing won't be so much of an issue..

enter image description here

Upvotes: 0

Views: 241

Answers (2)

El Tomato
El Tomato

Reputation: 6707

Test the following with autoreleasepool.

let mainDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let newResource = NSEntityDescription.insertNewObject(forEntityName: stopEntity, into: context)

for i in 1..<objectArray.count - 1 {
    autoreleasepool(invoking: { () -> () in
        let item: [String] = self.objectArray[i]
        s_stop_id = Int(item[0])
        s_stop_code = Int(item[1])
        s_stop_name = item[2]
        newResource.setValue(s_stop_id, forKey: "stop_id")
        newResource.setValue(s_stop_name, forKey: "stop_name")
        newResource.setValue(s_stop_code, forKey: "stop_code")

        do {
            try context.save()
        } catch let error as NSError  {
            print("Error While Saving Data: \(error.userInfo)")
        }    
    })
}

Upvotes: 2

Eduardo Leite
Eduardo Leite

Reputation: 71

you should probably instantiate the context and save outside the for, it would be something like this:

func loadDataBase() {

    let mainDelegate = UIApplication.shared.delegate as! AppDelegate
    let context = mainDelegate.persistentContainer.viewContext

    for i in 1..<objectArray.count - 1 {

        let item: [String] = objectArray[i]


        s_stop_id = Int(item[0])
        s_stop_code = Int(item[1])
        s_stop_name = item[2]



        let newResource = NSEntityDescription.insertNewObject(forEntityName: stopEntity, into: context)

        newResource.setValue(s_stop_id, forKey: "stop_id")
        newResource.setValue(s_stop_name, forKey: "stop_name")
        newResource.setValue(s_stop_code, forKey: "stop_code")
    }
    do {
            try context.save()

        } catch let error as NSError  {
            print("Error While Saving Data: \(error.userInfo)")
        }
}

Upvotes: 2

Related Questions