0

My application uses multiple threads with one managed object context per thread.

For clarity I will refer to the different managed object contexts as: moc1, moc2, ..., etc.

Let's assume we have two models with a simple one-many relationship:

User 1----* Document

When a user logs in I fetch the corresponding model from one of the contexts (eg. moc1).

(pseudo code)

UserModel *globalLoggedUser = ( Fetch the logged in user using moc1 )

I then store this user so that I can reference it later.

In another part of the application I need to loop through thousands of items from an array and create Document objects for it. Each document then needs to be bound to the current user. This happens in a different background thread (which has its own context)

for( NSString *documentName in documents) {
    ( Create new document using moc2 )

    ** THIS IS WHERE MY PROBLEM IS **
    // What I currently do:
    UserModel *tempUser = ( Fetch the logged in user using moc2 )
    ( bind new document to tempUser )

    // What I would like to do: 
    ( bind new document to globalLoggedUser )

    // Note that in this case tempUser and globalLoggedUser are the same user, except they are attached to different contexts.

}

As you can see, I would like to avoid having to fetch a new user into the current context each time.

The problem is, globalLoggedUser is part of moc1, whereas the new document is part of moc2 (or moc3, moc4, etc, depends on the thread).

So what's the best way to go about this? How can I globally save/cache an object and then use that same object to bind relationships in different contexts without incurring a penalty of having to fetch each time?

Thanks for any help you can provide.

nebs
  • 4,939
  • 9
  • 41
  • 70

1 Answers1

1

You are correct that you can't use the same NSManagedObject across threads.

From the Core Data Programming Guide:

Using thread confinement, you should not pass managed objects or managed object contexts between threads. To “pass” a managed object from one context another across thread boundaries, you either:

  • Pass its object ID (objectID) and use objectWithID: or existingObjectWithID:error: on receiving managed object context.

    The corresponding managed objects must have been saved—you cannot pass the ID of a newly-inserted managed object to another context.

  • Execute a fetch on the receiving context.

I think you'd be fine if you just fetched the logged in user with moc2 before you run the 'document' loop, as I don't see any reason to do the fetch each time inside the loop. (Is there some reason you are doing that?)

Don't worry about binding anything to the UserModel from thread 1, the tempUser you get from moc2 is referencing the same data in the database as globalLoggedUser.

Richard Lovejoy
  • 663
  • 10
  • 18