Core Data crashes forming a relationship between objects in different contexts
A Note is created on the main context, while a Category was fetched in a background context. Assigning the relationship crashes: Illegal attempt to establish a relationship 'category' between objects in different contexts.
Constraints:
- Keep the
Noteon the main context. - Do not disable Core Data validation and do not add a second store.
let note = Note(context: mainContext)
note.title = "Draft"
// `category` was fetched earlier in a background context
note.category = category // ❌ crashes: objects in different contexts
try mainContext.save()
Find and fix the bug.
A Core Data relationship can only join two NSManagedObjects in the same context. Here note is on the main context but category came from a background context, so note.category = category crashes. Fix it by re-fetching category in the main context via its objectID.
- ✗Assigning a relationship across two different
NSManagedObjectContexts - ✗Thinking the crash is a threading issue fixable with a queue hop alone
- ✗Using KVC to bypass the context check instead of translating via
objectID
- →Why is
objectIDsafe to pass between contexts when the object is not? - →When would you use
object(with:)instead ofexistingObject(with:)here?
A relationship can only join objects from the same context. Bring category into the main context by its objectID, then set the relationship there:
let note = Note(context: mainContext)
note.title = "Draft"
let categoryID = category.objectID // thread-safe identifier
let localCategory = try mainContext.existingObject(with: categoryID) as! Category
note.category = localCategory // both objects now live in mainContext
try mainContext.save()
objectID crosses context boundaries safely, whereas the NSManagedObject itself is bound to its context and that context's queue. If category lives in a background context, do the fetch and assignment inside mainContext.perform { … }.