Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does NSManagedObjectID change?

Tags:

ios

core-data

I'm not really sure whether the format of this question is good for this site.

Basically, does anyone know what has convinced Apple to make the design decision that NSManagedObjectID changes whenever you save the data to the persistent store?

I might be wrong, but that decision sounds quite questionable to me. There is no clear advantage (it's an UUID! It is unique!), and yet it makes passing objectID's --- it can change under your feet at any time when the object is saved.

It is a big problem for me because I use three MOC system (background MOC -> UI MOC -> Persistent MOC), objects are inserted into the background MOC and propagated upwards with a save. The save is asynchronous, as it has to propagate over three different MOCs and returning objects after they were created, yet before they are saved to the persistent store is quite painful, as I can't rely on passing objectID around.

Am I doing something particularly wrong? Does anyone know what is the advantage of UUID being mutable anytime with no notification?

My biggest question is why temporary managedObjectID is offered at all. Is there any point in it at all? Is it just to confuse people into attempting to use it?

like image 510
George Karpenkov Avatar asked Jun 14 '13 02:06

George Karpenkov


2 Answers

I'm a little confused why you keep saying the NSManagedObjectID is specifically a UUID. The URI representation may have a similar appearance to the UUID format, but I don't see anywhere in the docs that it says that "a NSManagedObjectID is a UUID" (and as I'll discuss below, it is more than that). Why exactly Apple designed it this way is beyond the scope of StackOverflow, so hopefully your question is really "what is Core Data's design, and how do I work with it?"

What the docs say (in Managed Object IDs and URIs) is that if you want to do this kind of object tracking, you should add your own UUID as a property:

You can sometimes benefit from creating your own unique ID (UUID) property which can be defined and set for newly inserted objects. This allows you to efficiently locate specific objects using predicates (though before a save operation new objects can be found only in their original context).

The reason that the NSManagedObjectID changes can be seen from the immutable data structure. It includes a persistentStore property. This cannot be known for certain until you actually save the object (you might call assignObject:toPersistentStore: for instance). Again, don't think of the NSManagedObjectID in terms of its URI representation; that's just a serialization format. The real ID includes the persistent store, as indicated in the docs:

Like the primary key in the database, an identifier contains the information needed to exactly describe an object in a persistent store, although the detailed information is not exposed.

That identifier cannot be finalized until the object is inserted.

like image 174
Rob Napier Avatar answered Oct 26 '22 02:10

Rob Napier


I'm not by any means an expert on Core Data, but my understanding is that the NSManagedObjectID is guaranteed to be unique under most circumstances. The exceptions are:

  • When you create a new object, but it has not yet been committed, its id will be temporary. You can check for this condition with isTemporaryId.
  • When the backing store has been mutated, i.e. if you're using iCloud and you migrate to a new version of your database.

Since you're talking about a single lifecycle, I assume we're looking at the first option. If that's the case, you should wait to get the id until after your changes have propagated up to the persistent store. I think you can get the id from the same object, i.e. create the object, retain a pointer to it, save the context, then get that object's id from the retained pointer. Caveat: I've never actually done this, it's just my conclusion based on my reading of the documentation.

Also, the temporary id should persist until you save the context, so you should only ever have to worry about this once -- after the first time the new object's context is saved.

Incidentally, it seems to me that CoreData must be implemented in this way. If they attempted to guarantee that the id was unique before actually inserting it into the persistent store, what would happen if two different contexts grabbed the same id, before committing? The only way to guarantee uniqueness / prevent a sort of race condition for ids is to find a unique id when inserting the record into the database... Otherwise, CoreData would have to somehow insert a dummy value for each record a child context inserts...

like image 33
samson Avatar answered Oct 26 '22 02:10

samson