Fetching an NSManagedObject with Unique Identifier? - iphone

Do NSManagedObjects come with any kind of unique identifier?
I need to fetch a couple of objects but there is a large chance they have identical attributes, so how can I, after fetching these objects, differentiate them?
Thanks.

Yes. Every NSManagedObject has an -objectId accessor which returns an NSManagedObjectID instance. These uniquely identify the object in question. You can then retrieve the object again using either of NSManagedObjectContext's methods -objectWithID: or -existingObjectWithID:error:.
Note that if the object has not yet been saved after insertion, the object ID will be a temporary ID that will change when it's saved. You can force a persistent ID to be assigned with -[NSManagedObjectContext obtainPermanentIDsForObjects:error:], although this is just as expensive as an actual save.

Related

store objectID in CoreData

If I wanted to store a list of objectsID's of different entities in CoreData what would the data type be for the objectID so I could use it in an NSFetchRequest to later retrive the Entity?
You can not store NSManagedObjectID, but you can store the object's URI representation, and use that to retrieve the object id using NSPersistentStoreCoordinator's managedObjectIDForURIRepresentation: method. Since you seem to want a list, i would save it in a new entity and store the necessary information to identify the id and the entity name it belongs to, among other relevant information.

Accessing managed object by objectID

I have three contexts:
masterMOC - private queue tied to the persistent store, so physical saves happen here
----mainMOC - main queue tied to the UI, child of masterMOC
-------backgroundMOC - private queue, child of mainMOC
Let's see I create an Employee object on the mainMOC, then save the mainMOC. Then I save the masterMOC (which writes to disk).
Now, I've saved the Employee NSManagedObjectID in a variable, objectID. I want to get this Employee on the backgroundMOC. Does [backgroundMOC objectWithId:objectID] serve this purpose? Will it go to the persistent store and fetch this object using that method? Or will I have to preform a fetch request?
Your'e doing it right. They want you to pass objects between MOContexts using ID's. objectWithId will hit the persistent store and load the object in a fresh state.
The only gotcha you have to worry about is this case.
You fetch an object or create a new object in a MOContext.
You try pass the objectID to another context WITHOUT SAVING
The new MOContext wont know about the updates, and if you created a new object the objectID wouldn't be in the persistent store, so I think it returns nil or it's not defined.
There is a WWDC video from this year titled 'Core Data Best Practices' that talks about nested MOC's. But to answer your question, yes, objectWithId will travel up through the fewest number of MOC levels to find the object. So if you call [backgroundMOC objectWithId:objectID] and the object exists in the mainMOC, it will get it from the mainMOC without having to go all the way to the masterMOC or the database.

Can I serialise a NSManagedObject?

I need to send an object (NSManagedObject (NSMO) subclass) up to a web service and retrieve it later. I was hoping I could somehow serialise it, but I'm hoping not to have to jump through the encoding hoops.
I can convert a simple NSMO object into a dictionary using:
[instance dictionaryWithValuesForKeys:instance.entity.attributesByName.allKeys];
However, my NSMO is a number of levels deep in terms of relationships to other NSMOs. What would be the best way to create a full serialised version of the object?
If you want to do this in a general way, you could write a recursive method serializedDictionary (either in a subclass of NSManagedObject or in a category) which:
Creates an empty NSMutableDictionary.
For each property, adds the key and value to the dictionary.
For each relationship, adds the relationship name as key and then calls serializedDictionary on the object and adds that as the value. If it's a to-many relationship, you'll have to put those values in an NSArray.
Note that if it's at all possible for a child object to be related back up to a parent (which is very possible if you have inverse relationships like Core Data recommends) you will either need to whitelist the relationships you save (easier) or pass along a set to keep track of which objects have already been serialized, so you don't encode them again (harder, I don't recommend this).

NSManagedObject identification number

Ok, it seems like I'm asking a noob question (maybe I am and I have just been overlooking important details), but I am looking for a "distinguishing" number/attribute about a generic NSManagedObject that I could use as an ID number (I cannot use the name b/c I want to allow the user to create entities with the same names). If this is not existent please explain how I would recreate this. I understand that I could just add an attribute for this and increment a static variable (ex: currentId) but if I do then I have to consider an entity being deleted then how do I logically place the next inserted entity at that index and then return to the last index.
Core Data does not have the notion of an auto-incremented ID field, keep in mind Core Data is an object graph, not a database. It just happens that a datastore could be backed by a database system, a perfect example is SqlLite.
NSManagedObjectId is kind of like a URL with a GUID to be unique. If you want some sort of auto-incremented id you will have to handle this on your own, there are obviously many different ways you might go about this. You could have a separate entity that stores the last id assigned and read it every time you create a new record, increment the value, use that as your new ID and increment the stored value. This would solve your delete problem if you don't want an ID to be re-used. There are obvious concurrency issues here that you may need to solve. Another approach could be to store the ID in a file on the file system, or in NSUserDefaults, just be sure to take account for concurrency and do not accidentally assign the same ID twice.
There is an objectID method for NSManagedObjects, although I do not believe that they are created in any kind of order.
Personally I would just use and ID attribute. What I don't understand is why deleting would cause any problems. The ID would just sit behind the scenes, there wouldn't be any real reason to show it to the user, right?
It seems like you could use a NSNumber identification row on your entities and then simply keep track of how many objects you have (either by keeping a var or fetching the max value from your storage).
Here I found a few examples that might help you achieve your goal.
link

keeping track of accessed objects in CoreData via objectID?

I want to have table in CoreData that holds a list of other CoreData objects I have accessed, for instance I have Clients and I want a table RecentClients that is simply holding this list and the date they were accessed.
Can I store the objectID and then do a fetch request based on that?
EDIT:
See Ben's answer below and then go here:
http://cocoawithlove.com/2008/08/safely-fetching-nsmanagedobject-by-uri.html
You'll want to convert the NSManagedObjectID to a string by calling its -URIRepresentation method. You can then convert the string back to an NSManagedObjectID using NSPersistentStore's -managedObjectIDForURIRepresentation: method.
If you store the strings, you should be able to do what you're describing, though you won't use a fetch request; you'll use -[NSManagedObjectContext objectWithID:]
How are you planning on storing the access date? If you make it an attribute of your Client entity, you can bump it each time the object is accessed and then use an NSFetchedResultsController that fetches Clients ordered by the access date. The downside is, of course, that you're modifying the instance every time you access it, which may not be ideal.
You could just create the RecentClients as another entity in your Core Data model. It would then have a one to many relationship with the Client entity.