Coredata Is Very Slow; Swift

Coredata is very slow; swift

If you have many objects of the same type, Core Data is naturally going to take a long time to save things. Doesn't matter what you do, it will take a while. What you can do is to configure the save to take places in a background thread as to not freeze your UI.

The easiest way is to create a background context for your main context. The idea is that your main context saves its data to the parent context, and the parent context is in charge of persisting data to disk. Basically like this:

Core Data Parent and Child Contexts

Because both your main context and parent context are running in memory, the save operation from the child to the parent is fast. Once the parent has your location objects, it will save in a background thread. It may still take a long time, but at the very least it should not freeze your UI.

And you can configure this in your code like this:

lazy var parentContext: NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType:.PrivateQueueConcurrencyType)
moc.persistentStoreCoordinator = self.coordinator
return moc
}()

lazy var context: NSManagedObjectContext = {
let moc = NSManagedObjectContext(concurrencyType:.MainQueueConcurrencyType)
// moc.persistentStoreCoordinator = self.coordinator
moc.parentContext = self.parentContext
return moc
}()

context will be the child context. You can see how easy it is to give it a parent context.

Then, to save your data:

class func save(moc:NSManagedObjectContext) {

moc.performBlockAndWait {

if moc.hasChanges {

do {
try moc.save()
} catch {
print("ERROR saving context \(moc.description) - \(error)")
}
}

if let parentContext = moc.parentContext {
save(parentContext)
}
}
}

(Code taken and slightly edited from the "Learning Core Data for iOS with Swift: A Hands-on Guide" book by Tim Roadley).

Swift CoreData: accessing relationship is slower than just fetching by predicate - is it designed that way?

Accessing via the relationship, then sorting and discarding 4950 / 5000 items means that all of that processing has to be done in memory. Using fetch requests means that you can get the database to do the work.

If you have a relationship between the library and its books, you can use that in a predicate. In your code above, that would be something like:

let predicate = NSPredicate(format: "library == %@", library)

That will likely be faster than storing the ID, unless you have an index added on library ID.

Core data slow processing updates on a background thread

I hit similar slow performance when upserting a large collection of objects. In my case I'm willing to keep the full change set in memory and perform a single save so the large volume of fetch requests dominated my processing time.

I got a significant performance improvement from maintaining an in memory cache mapping my resources' primary keys to NSManagedObjectIDs. That allowed me to use existingObjectWithId:error: rather than a fetch request for an individual object.

I suspect I might do even better by collecting the primary keys for all resources of a given entity description, issuing a single fetch request for all of them at once (batching those results as necessary), and then processing the changes to each resource.

Core data save takes too long

How big are these objects? How much data are you trying to save?

What type of persistent store are you using? SQLite?

What is your UI doing with this data after you save? Are you doing any kind of parsing of the data or display of the data?

What does Instruments say? Where does it say the time is being spent?

These are the first questions.

Core Data in no way should be taking that long to save the data. I suspect you are doing something in your User Interface that is being triggered by the save that is really taking the time. Time Profiler in instruments will tell us what is going on.

While I would not write this the way you are doing it, there is nothing wrong with the code you posted therefore the issue must be somewhere else. Instruments will tell us where to look.

Update

Thank you for posting the trace, it confirms my suspicions. If you look at where the time is being spent, 54% is in your NSFetchedResultsController and 20.6% is being spent in your TimelineViewController. What this means is that the save is very quick and then your UI is reacting very slowly to the changes. Turn off the merge changes notification to confirm. From there I would suggest digging deeper into your UI in time profiler and find out why it is so incredibly slow.

Looks like you are doing some complex string manipulation and other things in there that are very CPU intensive. Fix those and the speed will come back.



Related Topics



Leave a reply



Submit