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 ...

Erazorx
quelle

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];
Barry Wark
quelle
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;
Jim Correia
quelle
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).

Suragch
quelle
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.

Oscar Salguero
quelle
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
Yuriy Pavlyshak
quelle
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
}
Jarora
quelle
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
}
Philippe H. Regenass
quelle
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"))
Fattie
quelle
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");
}
Umit Kaya
quelle