CoreData NSFetchRequest with 'count' expression property is returning a NSManagedObjectID instead of an integer count

1

I have an NSFetchRequest set to fetch properties with enough information to populate a row displaying a user - their company, name, etc, and the number of things assigned to them. I send this to an NSFetchedResultsController which I'm using to populate rows in a table.

The property I'm having trouble with is the count of assigned items. A user can be a part of multiple projects, and I only care about issues within the current project and in a certain set of states.

So I have a predicate set up to get all issues assigned to this user, both in this project and in a given set of states:

NSPredicate* sequenceStatePredicate = [NSCompoundPredicate andPredicateWithSubpredicates:@[
        [NSPredicate predicateWithFormat:@"$assignment.workItem.sequence.project == %@", project],
        [NSPredicate predicateWithFormat:@"$assignment.workItem.sequence.state IN %@", [WorkSequence countableStates]]
    ]];

I then set up a count: expression for that predicate, on the assignments relationship of the user:

NSExpression *assignments = [NSExpression expressionForSubquery:[NSExpression expressionForKeyPath:@"assignments"]  usingIteratorVariable:@"assignment" predicate:sequenceStatePredicate];
NSExpression *count = [NSExpression expressionForFunction:@"count:" arguments:@[assignments]];
NSExpressionDescription *sequenceCountProperty = [[NSExpressionDescription alloc] init];
[sequenceCountProperty setExpression:count];
[sequenceCountProperty setExpressionResultType:NSInteger32AttributeType];
[sequenceCountProperty setName:WorkSequenceCount];

Finally, I set this expression as a property for my fetch request:

NSFetchRequest *fetchRequest = [NSFetchRequest fetchRequestWithEntityName:[User entityName]];
[fetchRequest setResultType:NSDictionaryResultType];
[fetchRequest setPropertiesToFetch:@[/* Some other properties */, sequenceCountProperty]];
[fetchRequest setPredicate:query.predicate];
...

This all works fine - except the result I get in the dictionary for the WorkSequenceCount key is an NSManagedObjectID, not an integer.

(lldb) po [[[[_fetchedResultsController fetchedObjects] objectAtIndex:0] objectForKey:WorkSequenceCount] class]
_NSCoreDataTaggedObjectID

The object ID appears to be equivalent to the expected count (note the p50 at the end - I expect the count to be 50 here, and I only have 3 Project objects in CoreData at this time):

(lldb) po [[[_fetchedResultsController fetchedObjects] objectAtIndex:0] objectForKey:WorkSequenceCount]
0xd000000000c80008 <x-coredata://1EB42655-9F98-4DFD-8A7A-BB65A108D300/Project/p50>

And the property expression is correct:

(lldb) po [[[[_fetchedResultsController fetchRequest] propertiesToFetch] objectAtIndex:4] expression]
count:(SUBQUERY(assignments, $assignment, $assignment.workItem.sequence.state IN {1, 2, 3, 5} AND $assignment.workItem.sequence.project == 0x16f93a90 <x-coredata://70C4F650-DADF-462C-A10A-55DA1E5978D3/Project/p1>))

...as is its result type (0x000000c8 == 200 == NSInteger32AttributeType):

(lldb) po [[[[_fetchedResultsController fetchRequest] propertiesToFetch] objectAtIndex:4] expressionResultType]
0x000000c8

If I log the SQL and run the request by hand on the SQLite file, I get the expected results.

If I remove the project filter from the predicate, I get an integer - so this appears to be related to including that. Obviously I can't do that, because then I get the number of items assigned to the user across all projects. No matter how I build the predicate statement (swapping the order of the AND, build it as one predicate with an AND myself instead of using NSCompoundPredicate, etc...) I can't change the result.

So, why is my fetch request returning a managed object ID when I explicitly tell it to give me an integer?

ios
objective-c
core-data
asked on Stack Overflow Apr 15, 2015 by Adam S

1 Answer

1

It's weird - a bug in CoreData, I think. It's certainly not honouring the expressionResultType. I've experienced it with much simpler expressions, and dodged it by using object attributes in expressions/predicates, rather than objects themselves. eg rather than counting assignments, try counting an attribute of the assignments (assuming there is an attribute that you know is not nil).

answered on Stack Overflow Apr 15, 2015 by pbasdf

User contributions licensed under CC BY-SA 3.0