I've got some Core Data code that follows Apple's sample code precisely (the Fetching Attribute Values that Satisfy a Given Function example). I'm using it to get the max value of a field, so I can then increment it when I insert the next object of that entity type.
I couldn't get the code to work at all, until I switched my Store Type from NSXMLStoreType
to NSSQLiteStoreType
, then all of a sudden everything seemed to be working. However, that's not the case. I noticed that it would always return the same value, even when I inserted objects with a higher one. But, after I quit and reopened (and thus the data was persisted and read back in), it would update with the new inserts.
So then I started committing and saving after each insert. After the first "autosave" though, I get the error below (twice in a row):
-[NSCFNumber count]: unrecognized selector sent to instance 0x100506a20
This occurs (two times in a rows) when I execute the fetch request once:
NSArray *objects = [context executeFetchRequest:request error:&error];
Update
I ran my code through the Zombies instrument, and was able to take a look at the object which is getting the error. The call that runs malloc
to allocate it is: -[NSUserDefaults(NSUserDefaults) initWithUser:]
. Since I don't have any of my own defaults set, I don't know what object this could be.
Update 2
I searched through all of my code for "release" and commented out every release
or autorelease
that the static analyzer didn't complain about. I still got the errors. I even went so far as to comment out every last release
/autorelease
in my code, and still got it. Now I'm fairly certain my own code isn't over-releasing.
Update 3
This post seems to be having the same problem, but his solution doesn't make sense. He changed the result type from NSDictionaryResultType
to NSManagedObjectResultType
, which produces an incorrect result. Instead of getting back a single value (the max
that I'm looking for, that returns back every object of my entity class in the managed object context.
Here are the top-most levels of the stack trace (when I have it break on the exception, the first time):
#0 0x7fff802e00da in objc_exception_throw
#1 0x7fff837d6110 in -[NSObject(NSObject) doesNotRecognizeSelector:]
#2 0x7fff8374e91f in ___forwarding___
#3 0x7fff8374aa68 in __forwarding_prep_0___
#4 0x7fff801ef636 in +[_NSPredicateUtilities max:]
#5 0x7fff800d4a22 in -[NSFunctionExpression expressionValueWithObject:context:]
#6 0x7fff865f2e21 in -[NSMappedObjectStore executeFetchRequest:withContext:]
#7 0x7fff865f2580 in -[NSMappedObjectStore executeRequest:withContext:]
I've seen this question on numerous forums elsewhere on the web, but no one has offered a workable solution. By popular request, I added my own code below. To explain slightly, my entity's name is Box
and the property I'm trying to get the value of is "sortOrder", an Int 32
attribute.
NSManagedObjectContext *context = [MyLibrary managedObjectContext];
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Box"
inManagedObjectContext:context]];
// Specify that the request should return dictionaries.
[request setResultType:NSDictionaryResultType];
// Create an expression for the key path.
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"sortOrder"];
// Create an expression to represent the function you want to apply
NSExpression *expression = [NSExpression expressionForFunction:@"max:"
arguments:[NSArray arrayWithObject:keyPathExpression]];
// Create an expression description using the minExpression and returning a date.
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];
// The name is the key that will be used in the dictionary for the return value.
[expressionDescription setName:@"maxSort"];
[expressionDescription setExpression:expression];
[expressionDescription setExpressionResultType:NSInteger32AttributeType];
// Set the request's properties to fetch just the property represented by the expressions.
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
// Execute the fetch.
NSError *error;
NSNumber *requestedValue = nil;
NSArray *objects = [context executeFetchRequest:request error:&error];
NSLog( @"objects: %@", objects );
if (objects != nil && [objects count] > 0) {
requestedValue = [[objects objectAtIndex:0] valueForKey:@"maxSort"];
} else {
[[NSApplication sharedApplication] presentError:error];
}
[expressionDescription release];
[request release];
NSLog( @"Max Sort Order: %@", requestedValue );
return requestedValue;