Illegal attempt to establish a relationship problem.

I pass a object from another viewcontroller and try to add a new record on coredata,

object is not nil , but I got the error message below, why? What is that mean "in different contexts"?

'NSInvalidArgumentException', reason: 'Illegal attempt to establish a relationship 'schedule' between objects in different contexts

Answered by NotMyName in 82042022

"in different contexts" means that the two managed objects have been created in different NSManagedObjectContext instances.


If you created a managed object context in the new view controller, you need to get a new NSManagedObject instance for the object:


let objectID = managedObject.objectID

let copy = context2.objectWithID(objectID)


See:

developer.apple.com/library/etc/redirect/xcode/ios/1151/documentation/Cocoa/Conceptual/CoreData/FrequentlyAskedQuestions.html

"How do I copy a managed object from one context to another?"

Accepted Answer

"in different contexts" means that the two managed objects have been created in different NSManagedObjectContext instances.


If you created a managed object context in the new view controller, you need to get a new NSManagedObject instance for the object:


let objectID = managedObject.objectID

let copy = context2.objectWithID(objectID)


See:

developer.apple.com/library/etc/redirect/xcode/ios/1151/documentation/Cocoa/Conceptual/CoreData/FrequentlyAskedQuestions.html

"How do I copy a managed object from one context to another?"

The best approach I've ever found is to use dedicated Queue for all database operations:


class Queues {

    private struct queues {
        static var dbQueue: dispatch_queue_t!
        static var dispatchToken: dispatch_once_t = 0
    }

    class var dbQueue: dispatch_queue_t {
        get {
            dispatch_once(&queues.dispatchToken, { () -> Void in
                queues.dbQueue = dispatch_queue_create("db_queue", nil)
            })
            return queues.dbQueue
        }
    }
}


and then in your Persistence.swift:


class func DoSomething() {
     dispatch_async(Queues.dbQueue, { () -> Void in
          ...
     })
}


if you need to send result back use the following:


class func DoSomething(closure:(SomeType)->()) {
     dispatch_async(Queue.dbQueue, { () -> Void in
          ...
               dispatch_async(dispatch_get_main_queue(), { () -> Void in
                      closure(result)
               })
     })
}


In this way you will never need to synchronize context objects because the access to the NSManagedObject objects happens is single context.


class Persistence {
   
    class var context : NSManagedObjectContext {
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        return appDelegate.managedObjectContext!
    }
     ...
}

Thanks a lot. You solved my problem.


When pass ManagedObject from last viewcontroller , it need to retrive it from managedContext(backgroundContext)

let objectID = schedule.objectID

let belongSchedule = self.cdh.backgroundContext?.objectWithID(objectID) as! Schedule

newDailyPlan.schedule = belongSchedule // schedule is relationship

self.cdh.saveContext(self.cdh.backgroundContext!)

Illegal attempt to establish a relationship problem.
 
 
Q