Cocoa Core Data effiziente Methode zum Zählen von Entitäten


174

Ich habe viel über Core Data gelesen. Aber was ist ein effizienter Weg, um über einen Entitätstyp zu zählen (wie SQL es mit SELECT count (1) tun kann ...). Jetzt habe ich diese Aufgabe gelöst, indem ich alle mit ausgewählt NSFetchedResultsControllerund die Anzahl der NSArray! Ich bin sicher, das ist nicht der beste Weg ...

Antworten:


303

Ich weiß nicht, ob die Verwendung von NSFetchedResultsController der effizienteste Weg ist, um Ihr Ziel zu erreichen (aber es kann sein). Der explizite Code zum Abrufen der Anzahl der Entitätsinstanzen lautet wie folgt:

// assuming NSManagedObjectContext *moc

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:entityName inManagedObjectContext:moc]];

[request setIncludesSubentities:NO]; //Omit subentities. Default is YES (i.e. include subentities)

NSError *err;
NSUInteger count = [moc countForFetchRequest:request error:&err];
if(count == NSNotFound) {
  //Handle error
}

[request release];

1
Auf Leopard möchten Sie countForFetchRequest: und nicht executeFetchRequest:
IlDan

Und überspringen, um das Prädikat festzulegen. Kein Prädikat:
Holen Sie

4
Nur zu Ihrer Information, count == 0, wenn für die spezifische Anforderung keine Ergebnisse vorliegen, NSNotFound = NSIntegerMax, sodass '// Handel-Fehler' nicht ausgeführt wird, wenn keine Ergebnisse vorliegen.
Absichten

Gibt es einen Tippfehler bei: setIncludesSubentities? Ich denke, die Dokumentation zeigt in "Entitäten" eher ein Kleinbuchstaben "e" als im Beispielcode das Großbuchstaben "E" an.
Mike

2
@LarsSchneider die Dokumentation für countForFetchRequest:error:Zustände, die NSNotFoundim Fehlerfall zurückgegeben werden. Im Allgemeinen besteht die NSErrorBehandlung in der Kakaokonvention darin, dass der Wert von errundefiniert (und häufig gefährlich) ist, wenn kein Fehler auftritt.
Barry Wark

61

Um klar zu sein, zählen Sie keine Entitäten, sondern Instanzen einer bestimmten Entität. (Um die Entitäten buchstäblich zu zählen, fragen Sie das verwaltete Objektmodell nach der Anzahl seiner Entitäten.)

Um alle Instanzen einer bestimmten Entität zu zählen, ohne alle Daten abzurufen, muss die Verwendung erfolgen -countForFetchRequest:.

Beispielsweise:

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity: [NSEntityDescription entityForName: entityName inManagedObjectContext: context]];

NSError *error = nil;
NSUInteger count = [context countForFetchRequest: request error: &error];

[request release];

return count;

32

Schnell

Es ist ziemlich einfach, die Gesamtzahl der Instanzen einer Entität in Core Data zu ermitteln:

let context = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
let fetchRequest = NSFetchRequest(entityName: "MyEntity")
let count = context.countForFetchRequest(fetchRequest, error: nil)

Ich habe dies im Simulator mit einer Objektanzahl von über 400.000 getestet und das Ergebnis war ziemlich schnell (wenn auch nicht sofort).


23

Ich füge das nur hinzu, um es noch effizienter zu machen ... und weil es nur eine Zählung ist, brauchen Sie keinen Eigenschaftswert und wie in einem der obigen Codebeispiele brauchen Sie auch keine Unterentitäten.

Der Code sollte also so aussehen:

int entityCount = 0;
NSEntityDescription *entity = [NSEntityDescription entityForName:@"YourEntity" inManagedObjectContext:_managedObjectContext];
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
[fetchRequest setEntity:entity];
[fetchRequest setIncludesPropertyValues:NO];
[fetchRequest setIncludesSubentities:NO];
NSError *error = nil;
NSUInteger count = [_managedObjectContext countForFetchRequest: fetchRequest error: &error];
if(error == nil){
    entityCount = count;
}

Ich hoffe es hilft.


10

Ich glaube, der einfachste und effizienteste Weg, Objekte zu zählen, besteht darin, den NSFetchRequestErgebnistyp auf zu setzen NSCountResultTypeund ihn mit der NSManagedObjectContext countForFetchRequest:error:Methode auszuführen .

NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] initWithEntityName:entityName];
fetchRequest.resultType = NSCountResultType;
NSError *fetchError = nil;
NSUInteger itemsCount = [managedObjectContext countForFetchRequest:fetchRequest error:&fetchError];
if (itemsCount == NSNotFound) {
    NSLog(@"Fetch error: %@", fetchError);
}

// use itemsCount

6

Ich habe eine einfache Dienstprogrammmethode für Swift 3 geschrieben, um die Anzahl der Objekte abzurufen.

static func fetchCountFor(entityName: String, predicate: NSPredicate, onMoc moc: NSManagedObjectContext) -> Int {

    var count: Int = 0

    moc.performAndWait {

        let fetchRequest: NSFetchRequest<NSFetchRequestResult> = NSFetchRequest(entityName: entityName)
        fetchRequest.predicate = predicate
        fetchRequest.resultType = NSFetchRequestResultType.countResultType

        do {
            count = try moc.count(for: fetchRequest)
        } catch {
            //Assert or handle exception gracefully
        }

    }

    return count
}

3

In Swift 3

  static func getProductCount() -> Int {
    let moc = (UIApplication.sharedApplication().delegate as! AppDelegate).managedObjectContext
    let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Product")
    let count = try! moc.count(for: fetchRequest)
    return count
}

1

Es ist wirklich nur das:

let kBoat = try? yourContainer.viewContext.count(for: NSFetchRequest(entityName: "Boat"))

"Boot" ist nur der Name der Entität auf Ihrem Datenmodellbildschirm:

Geben Sie hier die Bildbeschreibung ein

Was ist das Globale yourContainer?

Um Kerndaten zu verwenden, müssen Sie zu einem bestimmten Zeitpunkt in Ihrer App nur einmal loslegen

var yourContainer = NSPersistentContainer(name: "stuff")

Dabei ist "stuff" einfach der Name der Datenmodelldatei.

Geben Sie hier die Bildbeschreibung ein

Sie hätten einfach einen Singleton dafür,

import CoreData
public let core = Core.shared
public final class Core {
    static let shared = Core()
    var container: NSPersistentContainer!
    private init() {
        container = NSPersistentContainer(name: "stuff")
        container.loadPersistentStores { storeDescription, error in
            if let error = error { print("Error loading... \(error)") }
        }
    }
    
    func saveContext() {
        if container.viewContext.hasChanges {
            do { try container.viewContext.save()
            } catch { print("Error saving... \(error)") }
        }
    }
}

Also von überall in der App

core.container

ist dein Container,

In der Praxis ist es also einfach, die Anzahl der Entitäten zu ermitteln

let k = try? core.container.viewContext.count(for: NSFetchRequest(entityName: "Boat"))

0

Wenn Sie die Anzahl für einen bestimmten prädizierten Abruf ermitteln möchten, ist dies meiner Meinung nach der beste Weg:

NSError *err;
NSUInteger count = [context countForFetchRequest:fetch error:&err];

if(count > 0) {
NSLog(@"EXIST"); 
} else {
NSLog(@"NOT exist");
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.