2012-05-01 15 views

Respuesta

58

Se establece el fetchLimit a 1 y ordenar por personId en orden descendente. Por ejemplo:

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:@"Person"]; 

fetchRequest.fetchLimit = 1; 
fetchRequest.sortDescriptors = @[[NSSortDescriptor sortDescriptorWithKey:@"personId" ascending:NO]]; 

NSError *error = nil; 

id person = [managedObjectContext executeFetchRequest:fetchRequest error:&error].firstObject; 
+1

agradecimiento de su ayuda – Eyal

+1

Si usted no tiene un índice en el atributo de ser ordenados, entonces, esta técnica es más caro, O (n log n), que la exploración de una lista de un valor máximo, O (n), como se describe en la respuesta de @Uilleann. Dicho esto, si tiene un índice sobre el atributo que se está ordenando, ambas técnicas deberían ser las mismas. –

+0

¿Vale la pena establecer 'fetchBatchSize' en 1 también, o está implícito en que 'fetchLimit' sea 1? – Benjohn

21

Es necesario utilizar un NSFetchRequest con un NSPredicate para especificar su consulta ...

Adaptado de las instrucciones de programación de predicados de Apple:

NSFetchRequest *request = [[[NSFetchRequest alloc] init] autorelease]; 
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Person" 
    inManagedObjectContext:managedObjectContext]; 
[request setEntity:entity]; 

request.predicate = [NSPredicate predicateWithFormat:@"personId==max(personId)"]; 
request.sortDescriptors = [NSArray array]; 

NSError *error = nil; 
NSArray *array = [managedObjectContext executeFetchRequest:request error:&error]; 
15

El método recomendado es utilizar Apple Recommended Method NSExpression. Esperaría que esto fuera menos costoso que usar un ordenamiento. Si lo piensas bien, con un tipo, deberías tomar todos los registros para clasificarlos y mantener el máximo. Con una expresión solo tendrías que leer la lista y mantener en la memoria el máximo.

Aquí se muestra un ejemplo que utilizo con NSDate

- (NSDate *)lastSync:(PHAssetMediaType)mediaType { 
    NSEntityDescription *entity = [NSEntityDescription entityForName:kMediaItemEntity inManagedObjectContext:self.managedObjectContext]; 

    NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init]; 
    fetchRequest.entity = entity; 
    fetchRequest.resultType = NSDictionaryResultType; 

    NSMutableArray *predicates = [NSMutableArray array]; 
    [predicates addObject:[NSPredicate predicateWithFormat:@"%K=%d", kMediaType,mediaType]]; 
    [predicates addObject:[NSPredicate predicateWithFormat:@"%K=%d", kMediaProviderType,self.mediaProviderType]]; 
    NSPredicate *predicate = [NSCompoundPredicate andPredicateWithSubpredicates: predicates]; 
    fetchRequest.predicate = predicate; 

    // Create an expression for the key path. 

    NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:kSyncTime]; 
    // Create an expression to represent the function you want to apply 

    NSExpression *maxExpression = [NSExpression expressionForFunction:@"max:" 
                  arguments:@[keyPathExpression]]; 

    // Create an expression description using the maxExpression and returning a date. 
    NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init]; 
    [expressionDescription setName:@"maxDate"]; 
    [expressionDescription setExpression:maxExpression]; 
    [expressionDescription setExpressionResultType:NSDateAttributeType]; 

    // Set the request's properties to fetch just the property represented by the expressions. 
    fetchRequest.propertiesToFetch = @[expressionDescription] ; // @[kSyncTime]; 

    NSError *fetchError = nil; 
    id requestedValue = nil; 

    // fetch stored media 
    NSArray *results = [self.managedObjectContext executeFetchRequest:fetchRequest error:&fetchError]; 
    if (fetchError || results == nil || results.count == 0) { 
     return [NSDate dateWithTimeIntervalSince1970:0]; 
    } 
    requestedValue = [[results objectAtIndex:0] valueForKey:@"maxDate"]; 
    if (![requestedValue isKindOfClass:[NSDate class]]) { 
     return [NSDate dateWithTimeIntervalSince1970:0]; 
    } 
    DDLogDebug(@"sync date %@",requestedValue); 
    return (NSDate *)requestedValue; 
} 
+1

Esta debería ser la respuesta aceptada – shannoga

+0

Parece que el enfoque es realmente el mejor, pero parece que no funciona en la tienda en memoria: http://stackoverflow.com/questions/19301181/exception -raised-by-nsexpressiondescription-with-core-data-in-memory-store – oradyvan

+0

Me funcionó hasta que migré el proyecto a Swift 3. Apple, para un bien mayor, introdujo peticiones de búsqueda fuertemente tipadas, que no funcionan con este enfoque , provocando el error "No se pudo emitir el valor de tipo 'NSKnownKeysDictionary1' (0x106019870) a 'NSManagedObject' (0x106019b18) .'. Quizás la solución sea utilizar el método 'execute' de MOC, pero parece tener un nivel demasiado bajo, y volveré al método de 'clasificación'. –

4

La respuesta dada anteriormente usando NSExpression es correcta. Aquí está la versión Swift.

private func getLastContactSyncTimestamp() -> Int64? { 

let request: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest() 
request.entity = NSEntityDescription.entity(forEntityName: "Contact", in: self.moc) 
request.resultType = NSFetchRequestResultType.dictionaryResultType 

let keypathExpression = NSExpression(forKeyPath: "timestamp") 
let maxExpression = NSExpression(forFunction: "max:", arguments: [keypathExpression]) 

let key = "maxTimestamp" 

let expressionDescription = NSExpressionDescription() 
expressionDescription.name = key 
expressionDescription.expression = maxExpression 
expressionDescription.expressionResultType = .integer64AttributeType 

request.propertiesToFetch = [expressionDescription] 

var maxTimestamp: Int64? = nil 

do { 

    if let result = try self.moc.fetch(request) as? [[String: Int64]], let dict = result.first { 
     maxTimestamp = dict[key] 
    } 

} catch { 
    assertionFailure("Failed to fetch max timestamp with error = \(error)") 
    return nil 
} 

return maxTimestamp 
} 

donde moc es un NSManagedObjectContext.

1

Swift 3

let request:NSFetchRequest = Person.fetchRequest() 

let sortDescriptor1 = NSSortDescriptor(key: "personId", ascending: false) 

request.sortDescriptors = [sortDescriptor1] 

request.fetchLimit = 1 

do { 
    let persons = try context.fetch(request) 
    return persons.first?.personId 
} catch { 
    print(error.localizedDescription) 
} 
Cuestiones relacionadas