I'm trying to perform a fetch to retrieve managed objects from the context using an array of object IDs I gathered from a separate context. However, the fetch comes back with an empty array.
From the "Retrieving Specific Objects" section of the "Core Data Programming Guide" link:
If your application uses multiple contexts and you want to test whether an object has been deleted from a persistent store, you can create a fetch request with a predicate of the form self == %@. The object you pass in as the variable can be either a managed object or a managed object ID..."
If you need to test for the existence of several objects, it is more efficient to use the IN operator than it is to execute multiple fetches for individual objects, for example:
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"self IN %@", arrayOfManagedObjectIDs];
While this is talking about testing for object deletion, I presumed if the objects are not deleted then the results array is not empty, and will contain the actual NSManagedObjects. However, when I execute this code:
- (NSArray *)managedObjectsOfEntityName:(NSString *)entityName fromObjectIDs:(NSArray *)objectIDs managedObjectContext:(NSManagedObjectContext *)managedObjectContext
{
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:entityName];
request.predicate = [NSPredicate predicateWithFormat:@"self IN %@", objectIDs];
__autoreleasing NSError *error = nil;
NSManagedObjectID *testID = objectIDs[0];
NSManagedObject *obj = [managedObjectContext existingObjectWithID:testID error:&error];
if (!obj)
{
NSLog(@"Unable to perform fetch. Error: %@", error);
}
error = nil;
NSArray *results = [managedObjectContext executeFetchRequest:request error:&error];
if (!results)
{
NSLog(@"Unable to perform fetch. Error: %@", error);
}
return results;
}
The results array is non-nil and empty, while obj is properly populated.
I've added the explicit call to existingObjectWithID: as a sanity check, and it comes back with the expected object, without error.
Here's the debugger output for the pertinent variables:
(lldb) po entityName
Foo
(lldb) po objectIDs
<__NSArrayI 0x1170d4950>(
0xd0000000055c0082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p343>,
0xd000000008e80082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p570>,
0xd000000008840082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p545>,
0xd000000006040082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p385>,
0xd000000007740082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p477>,
0xd000000008280082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p522>,
0xd000000008e40082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p569>
)
(lldb) po request
<NSFetchRequest: 0x10f338840> (entity: Foo; predicate: (SELF IN {
0xd0000000055c0082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p343>,
0xd000000008e80082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p570>,
0xd000000008840082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p545>,
0xd000000006040082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p385>,
0xd000000007740082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p477>,
0xd000000008280082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p522>,
0xd000000008e40082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p569>});
sortDescriptors: ((null)); type: NSManagedObjectResultType; )
(lldb) po request.predicate
SELF IN {
0xd0000000055c0082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p343>,
0xd000000008e80082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p570>,
0xd000000008840082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p545>,
0xd000000006040082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p385>,
0xd000000007740082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p477>,
0xd000000008280082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p522>,
0xd000000008e40082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p569>}
(lldb) po testID
0xd0000000055c0082 <x-coredata://CEB1EDA5-7F7A-4342-85E5-6C2E261308CC/Foo/p343>
(lldb) p testID.isTemporaryID
(bool) $7 = false
(lldb) p obj
(NSManagedObject *) $9 = 0x000000010f338630
(lldb) po results
<__NSArrayI 0x10f205c70>(
)
(lldb) po testID.entity
nil
The nil entity on the testID is strange, but I'm not sure that's "bad."
So, I'm obviously at a loss as to why the fetch is coming back empty. The entity name is correct, the fetch and predicate look good, and the object is in the context, but still zero results.
Additional Context:
Essentially, the larger picture is that I have a background operation which uses its own Managed Object Context (MOC) to perform some work. The results of that work are needed on the main queue, so I package up the objectIDs resulting from the work and pass those to the main queue. On the main queue I need the actual managed objects back, so I'm trying to fetch them, by objectID, from the main queue's MOC. I realize I can use objectWithID: or existingObjectWithID:error: or even objectRegisteredForID: on the MOC to get these objects, but each have their own special issues:
objectWithID:might return an object which is bogus if the object is not in the context, and if it is in the context it will return a fault.existingObjectWithID:error:is great, since we'll get backnil(rather than a bogus object) but it too returns a fault.objectRegisteredForID:will returnnilif the object is not in the context already.
So, if I use either objectWithID: or existingObjectWithID:error: in a loop to get a bunch of objects, that's potentially n trips to the persisted store to fault the objects, meaning performance is going to be potentially awful. If I use objectRegisteredForID: I might not get the object at all if it happens to not already be in the main queue's MOC.
So, rather than try to iterate over the array, I expected a fetch request would limit the overhead of interacting with the persistance store and return all the objects I needed in one fell swoop.
Addition:
As an aside, the issue really feels like it has to do with the @"self IN %@" predicate, since I can remove that predicate and fetch all objects of entityName without issue. I have also tried @"objectID IN %@" as the predicate with the same (zero) results.
entityis a clue: there is something fishy about your object IDs. Your posted code looks fine. Is theFooentity correct? - Mundientityattribute is nil is extremely suspicious. I'm not sure what would cause that, but it makes the ID objects suspect of being bogus or broken in some way. - Tom Harrington