Reputation: 2562
Below, I have 3 snippets of code related to CoreData fetching objects in different threads in different ways. One of these ways is crashing with EXC_BAD_INSTRUCTION when I am trying to read the data after fetching it from DB even though the fetching and reading is being done on the same thread.
print("hello: current thread is \(Thread.current)")
let moc = self.getChildMoc()
moc.performAndWait {
let contacts = PPContactSyncHelper.contactsIfExistsWith(connectIds: connectIds, moc: moc)
contacts.forEach { contact in
print("hello: 2. current thread is \(Thread.current)")
print("hello: \(contact.connectId)")
}
}
DispatchQueue.main.async {
let abContacts = PPContactSyncHelper.contactsIfExistsWith(connectIds: connectIds, moc: self.mainContext)
abContacts.forEach { abContact in
print("hello: \(abContact.connectId)")
}
}
let contacts = PPContactSyncHelper.contactsIfExistsWith(connectIds: connectIds,
moc: moc)
contacts.forEach { contact in
print("hello: 2. current thread is \(Thread.current)")
print("hello: \(contact.connectId)")
}
The last snippet is the one that causes the issue while others can read the data successfully.
This is what I am doing.
The function PPContactSyncHelper.contactsIfExistsWith
fetches the data from coredata inside the performAndWait block using the context provided.
What am I missing here?
Upvotes: 2
Views: 916
Reputation: 70936
With managed object contexts, you always need to use perform
or performAndWait
. Except for one situation: If you're using a main queue managed object context and you are running on the main queue, you can skip those methods.
In your examples:
performAndWait
. It's a private queue (not main queue) context, and you used it correctly.DispatchQueue.main.async
. This is the one exception I mentioned above, so you're OK where.perform
or performAndWait
. You need to use one of those here to avoid crashing. You're on the same thread as example 1, but that doesn't matter. What's important is whether your Core Data code runs on the context's queue.Upvotes: 1
Reputation: 2562
The understanding of how NSManagedObjectContext
is created and which thread it is associated with is incorrect. When a NSManagedObjectContext
is created on a particular thread using initWithConcurrencyType
that does not mean that particular thread is NSManagedObjectContext
's thread. It is just created on that thread and nothing else. Only when we call perform
or performAndWait
on NSManagedObjectContext
, the block that we pass is run on the NSManagedObjectContext
's thread. The results depict the same scenario.
However, if the NSManagedObjectContext
is created with init
only without concurrency type then current thread would be NSManagedObjectContext
's thread.
Upvotes: 0