128

I can easily get an object's ID in Core Data using the following code:

NSManagedObjectID *moID = [managedObject objectID];

However, is there a way to get an object out of the core data store by giving it a specific object ID? I know that I can do this by using an NSFetchRequest, like this:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Document" inManagedObjectContext:managedObjectContext];
[fetchRequest setEntity:entity];

NSPredicate *predicate = [NSPredicate predicateWithFormat:@"(objectID = %@)", myObjectID];
[fetchRequest setPredicate:predicate];

However, I'd like to do it in a way that does not initiate its own fetch request. Any ideas?

Demitri
  • 13,134
  • 4
  • 40
  • 41
Jason
  • 14,517
  • 25
  • 92
  • 153
  • But with the fetch request way you can set properties or relations to be pre-fetched which will give you excellent efficiency rather than many more queries as you access things. – malhal Oct 12 '16 at 15:24

3 Answers3

215

You want:

-(NSManagedObject *)existingObjectWithID:(NSManagedObjectID *)objectID
                                   error:(NSError **)error

Fetches the object from the store that has that ID, or nil if it doesn't exist.

(Be aware: there are two methods on NSManagedObjectContext with similar-seeming names that tripped me up. To help keep them straight, here's what the other two do:

-(NSManagedObject *)objectWithID:(NSManagedObjectID *)objectID

...will create a fault object with the provided objectID, whether or not such an object actually exists in the store. If it doesn't exist, anything that fires the fault will fail unless you insert the object first with NSManagedObjectContext's insertObject:. The only use I've found for this is copying objects from store to store while preserving ObjectIDs.

-(NSManagedObject *)objectRegisteredForID:(NSManagedObjectID *)objectID

...will return the object that has that ID, if it has been fetched from the store by this managedObjectContext. If anyone knows what this method is useful for, please comment.)

[eta.: Another important difference between the first method and the other two is that existingObjectWithID:error: never returns a fault; it always fetches the whole object for you. If you're trying to avoid that (e.g. working with an expensive-to-fetch object with a big blob property), you have to be clever with objectWithID: or objectRegisteredForID:, which don't fire faults; or use a properly configured fetch request.]

rgeorge
  • 7,385
  • 2
  • 31
  • 41
  • 11
    `-(NSManagedObject *)objectRegisteredForID:(NSManagedObjectID *)objectID` is probably useful when you just want to see if an object already exists in context and don't want to fetch it. – Tony Jan 21 '12 at 02:01
  • My situtation. On `-tableView:didSelectRowAtIndexPath:` UIAlertView with yes/no is displayed. On "yes" - there is some work with object. I use `NSFetchedResultsController` + background CoreData updates from remote. So I can't store object: while alert is on the screen, storage can be updated and object removed. I store objectId, then retrieve it once more in alert delegate. Because I use `NSFetchedResultsController` - all necessary objects are already in context by this moment. Moreover, when there is no object in context, CoreData shouldn't make useless fetching attemp. – kpower Jul 21 '12 at 12:03
  • nice answer, thank you! these method names are really tricky. it's easy to mess everything up with the wrong one – jackal Sep 02 '12 at 12:51
  • Great answer, thanks for clarification about `objectWithId:` - the need of calling `insertObject` first to prevent a raise of exception on attempt to fire a fault was indeed unobvious to me. – Stanislav Pankevich Jul 31 '13 at 17:52
  • 3
    `objectRegisteredForID:` is useful when you have a list of objectIDs from an operation in another context, and you only want to update the ones that may have stale data in the local context. This keeps your object graph (and therefore memory usage) in check, and it's better than looping through `-registeredObjects` and checking objectIDs to see if an object is faulted in for your context. – Sterling Archer Nov 13 '13 at 18:58
5

objectWithID: is the method you are looking for, and it is the recommended way to do this. objectWithID: will efficiently use the NSManagedObjectContext to pull the object only as many levels as needed - unlike some of the other means of doing this. objectWithID: will correctly use in-memory information in parent contexts, the persistent store coordinator, and the persistent store itself before going to the backing storage.

This is covered in depth in the WWDC 2012 session "Core Data Best Practices".

quellish
  • 21,123
  • 4
  • 76
  • 83
4

Swift 5 version:

https://developer.apple.com/documentation/coredata/nsmanagedobjectcontext/1506686-existingobject

there are also methods object(with:) or registeredObject(for:). Depending on what you need.