4

Is there an easy (or just reliable) way to find the max value of a core data attribute? Apple's example just does not work (plus it is ridiculously long and complicated for such a simple task). I have spent almost a day on this and haven't been able to find a satisfactory answer. Please help!

I get the same error as in this question: -[NSCFNumber count]: unrecognized selector. Like him, I haven't been able to find a solution to the problem.

This asker thinks he solved the same problem but, like someone else commented, the answer here is apparently wrong.

This question also has trouble with exactly the same code but at least the asker actually didn't get at an exception. It appears that he couldn't get it to work properly though and ended up using a different solution but didn't say what.

One person here got around it by retrieving results sorted and using the top value. Not ideal! However, if I cannot find a solution soon, I think I will have to do the same, or restructure my model or business rules or create and maintain a MaxValue class in my model to get around this...

Community
  • 1
  • 1
stifin
  • 1,390
  • 3
  • 18
  • 28

2 Answers2

3

I found this in the core data programing guide under fetching specific values. It refers to a minimum, but it answers your question. Not as easy as one would hope, but it isn't that hard to follow.

NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Event" inManagedObjectContext:context];
[request setEntity:entity];
// Specify that the request should return dictionaries.
[request setResultType:NSDictionaryResultType];
// Create an expression for the key path.
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"creationDate"];
// Create an expression to represent the minimum value at the key path 'creationDate'
NSExpression *minExpression = [NSExpression expressionForFunction:@"min:" 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:@"minDate"];
[expressionDescription setExpression:minExpression];
[expressionDescription setExpressionResultType:NSDateAttributeType];
// Set the request's properties to fetch just the property represented by the expressions.
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];
// Execute the fetch.
NSError *error = nil;
NSArray *objects = [managedObjectContext executeFetchRequest:request error:&error];
if (objects == nil) {
    // Handle the error
}
else {
    if ([objects count] > 0) {
        NSLog(@"Minimum date: %@", [[objects objectAtIndex:0] valueForKey:@"minDate"]);
    }
}



[expressionDescription release];

[request release];
  • thanks but this is the same example that has caused problems for the people whose questions I've linked to in my original posting. I also encountered the same issue as those people and was not able to find an answer that helped me make it work. In any case, I totally agree about "not as easy as one would hope": IMHO, the authors of these methods should be embarrassed at the level of verbosity and counter-intuitiveness they're imposing in this type of a framework. – stifin Jun 12 '11 at 14:55
  • I haven't had a chance to try @grady's answer yet because I moved on after finding a workaround (i.e. use the first object returned from a sorted descending fetch request). The workaround is clearly suboptimal (fetching all objects when I only want one) so I intend to go back and try @grady's answer. – stifin Jun 12 '11 at 15:49
  • This is excellent. I wonder if we have any performance gains by using this approach as opposed to doing NSFetchRequest with limit 1 and sort descriptor for a given attribute. – raven_raven Jun 16 '16 at 18:45
0

have a NSManagedObject Subclass called TestEntity, which has one double property called tesetID.

-(double)getNextIndex
{
    NSFetchRequest * request = [[NSFetchRequest alloc] init];
    [request setEntity:[NSEntityDescription entityForName:@"TestEntity" inManagedObjectContext:self.managedObjectContext]];
    NSError * err = nil;
    NSArray * array = [self.managedObjectContext executeFetchRequest:request error:&err];
    NSNumber * value = [array valueForKeyPath:@"@max.testID"];

    return [value doubleValue]+1;
}
-(void)test
{
 for (int i = 0; i<25 ; i++) {
        TestEntity * entity = [[TestEntity alloc] initWithEntity:[NSEntityDescription entityForName:@"TestEntity" inManagedObjectContext:self.managedObjectContext] insertIntoManagedObjectContext:self.managedObjectContext];
        entity.testID = [NSNumber numberWithDouble:[self getNextIndex]];
        NSLog(@"our testID is set as: %@",entity.testID);
    }

}
Grady Player
  • 14,399
  • 2
  • 48
  • 76
  • no, I mean, for example, what is the age of the oldest employee? or what was the greatest studentID I've assigned to a student? in SQL terms, it would be extremely simple: `select max(studentID) from student` – stifin Jun 07 '11 at 14:21
  • you've pointed me back at the "solution" that I said in my original question does _not_ work for me. However, I had another stab at it. I managed to avoid [\[-NSCFNumber count\]:unrecognized selector](http://stackoverflow.com/questions/4387403/nscfnumber-count-unrecognized-selector/6259860#6259860) _but_ when I call max repeatedly, increment and store it in a new object, the max does not always return the latest value. So, e.g. create obj with StudentID, get max StudentID, create new obj with ++maxStudentID. After 10 calls, every 2 or 3 objects have the same StudentID! – stifin Jun 08 '11 at 16:49
  • the most reliable solution I've found so far is to return sorted descending StudentIDs and take the first one – stifin Jun 08 '11 at 16:53
  • Ok I am going to hit this with some code. and post an answer. – Grady Player Jun 08 '11 at 17:50
  • OK, thanks. I updated what I did to avoid that error (by removing the line `[request setResultType:NSDictionaryResultType];` [here](http://stackoverflow.com/questions/4387403/nscfnumber-count-unrecognized-selector/6259860#6259860) – stifin Jun 08 '11 at 18:50