2012-05-01 16 views

Odpowiedz

58

można ustawić fetchLimit do 1 i sortować według personId w kolejności malejącej. Np:

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

dzięki waszej pomocy – Eyal

+1

Jeśli nie mają indeks atrybutu są sortowane, a następnie technika ta jest droższa, O (n log n), niż skanowanie listy za maksymalna wartość, O (n), jak opisano w odpowiedzi @ Uilleanna. To powiedziawszy, jeśli masz indeks na sortowanym atrybucie, obie techniki powinny być takie same. –

+0

Czy warto ustawić 'fetchBatchSize' na 1, czy jest to niejawne w' fetchLimit' będącym 1? – Benjohn

21

Musisz użyć NSFetchRequest z NSPredicate określić zapytanie ...

Adaptacja Apple predykatów progamming Przewodnik:

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

Zalecanym sposobem jest użycie Apple Recommended Method NSExpression. Spodziewałbym się, że będzie to mniej kosztowne niż przy sortowaniu. Jeśli o tym pomyślisz, z pewnym rodzajem musiałbyś wziąć wszystkie rekordy, posortować je i zachować maksymalny. Z wyrażeniem musisz po prostu przeczytać listę i zachować w pamięci maksimum.

Oto przykład korzystać z 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

To powinno być zaakceptowaną odpowiedzią. – shannoga

+0

Wygląda na to, że podejście jest naprawdę najlepsze, ale wygląda na to, że nie działa w magazynie w pamięci: http://stackoverflow.com/questions/19301181/exception -rejestrowany przez-nse expressioniondescription-with-core-data-in-memory-store – oradyvan

+0

To działało dla mnie, dopóki nie przeniosłem projektu do Swift 3. Apple, dla większego dobra, wprowadziło silnie typowane żądania pobierania, które nie działają z tym podejściem , powodując "Nie można rzucić wartość typu" NSKnownKeysDictionary1 "(0x106019870) na błąd" NSManagedObject "(0x106019b18).". Być może praca polega na użyciu metody 'execute' w MOC, ale wydaje się zbyt niski poziom i powrócę do metody" sortowania ". –

4

odpowiedzi udzielonej powyżej używając NSExpression jest poprawna. Oto wersja 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 
} 

gdzie moc jest 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) 
} 
Powiązane problemy