risposta

58

Si imposta il fetchLimit per 1 e ordina per personId in ordine decrescente. Ad esempio:

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

grazie del vostro aiuto – Eyal

+1

Se non si dispone di un indice per l'attributo di essere ordinati, allora questa tecnica è più costoso, O (n log n), che la scansione di una lista per un valore massimo, O (n), come descritto nella risposta di @ Uilleann. Detto questo, se hai un indice sull'attributo che viene ordinato, allora entrambe le tecniche dovrebbero essere le stesse. –

+0

Vale la pena anche impostare 'fetchBatchSize' su 1, o è implicito in' fetchLimit' essere 1? – Benjohn

21

È necessario utilizzare un NSFetchRequest con un NSPredicate per specificare la vostra richiesta ...

Adattato da Apple Predicate Progamming Guida:

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

Il metodo consigliato è quello di utilizzare Apple Recommended Method NSExpression. Mi aspetterei che questo sarebbe meno costoso rispetto all'utilizzo di un ordinamento. Se ci pensate, con una specie dovrete prendere tutti i record per ordinarli e mantenere il massimo. Con un'espressione dovresti solo leggere l'elenco e mantenere in memoria il massimo.

Ecco un esempio che uso 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

Questa dovrebbe essere la risposta accettata – shannoga

+0

Sembra che l'approccio sia davvero il migliore, tuttavia sembra che non funzioni sullo store in-memory: http://stackoverflow.com/questions/19301181/exception -raed-by-nsexpressiondescription-with-core-data-in-memory-store – oradyvan

+0

Ha funzionato per me fino a quando ho migrato il progetto a Swift 3. Apple, per una maggiore utilità, ha introdotto richieste di recupero fortemente tipizzate, che non funzionano con questo approccio , causando 'Impossibile eseguire il cast del valore di tipo 'NSKnownKeysDictionary1' (0x106019870) su 'NSManagedObject' (0x106019b18) .'. Forse il problema è usare il metodo 'execute' di MOC, ma sembra troppo basso, e tornerò al metodo' ordina '. –

4

La risposta di cui sopra usando NSExpression è corretta. Ecco la versione 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 
} 

dove moc è 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) 
} 
Problemi correlati