Cocoa Core Data modo efficiente per contare le entità


174

Ho letto molto su Core Data .. ma qual è un modo efficace per fare un conteggio su un tipo di entità (come SQL può fare con SELECT count (1) ...). Ora ho appena risolto questo compito selezionando tutto con NSFetchedResultsControllere ottenendo il conteggio del NSArray! Sono sicuro che questo non è il modo migliore ...

Risposte:


303

Non so se usare NSFetchedResultsController sia il modo più efficiente per raggiungere il tuo obiettivo (ma potrebbe essere). Il codice esplicito per ottenere il conteggio delle istanze di entità è di seguito:

// 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
Su Leopard vuoi usare countForFetchRequest: e non executeFetchRequest:
IlDan,

E salta per impostare il predicato. Nessun predicato: ottieni tutti gli oggetti che corrispondono alla descrizione dell'entità
IlDan,

4
Cordiali saluti, count == 0 se non ci sono risultati per la richiesta specifica, NSNotFound = NSIntegerMax, quindi '// Handel error' non verrà eseguito se non ci sono risultati.
Intende il

C'è un errore di battitura: setIncludesSubentities? Penso che la documentazione indichi una "e" minuscola in "entità" anziché la "E" maiuscola nel codice di esempio.
Mike,

2
@LarsSchneider la documentazione per gli countForFetchRequest:error:stati che NSNotFoundviene restituita in caso di errore. In generale, la NSErrorgestione in convenzione Cocoa è che il valore di errè indefinito (e spesso pericoloso) se non si verifica alcun errore.
Barry Wark,

61

Per essere chiari, non stai contando le entità, ma le istanze di una particolare entità. (Per contare letteralmente le entità, chiedi al modello a oggetti gestito il conteggio delle sue entità.)

Per contare tutte le istanze di una determinata entità senza recuperare tutti i dati, l'uso -countForFetchRequest:.

Per esempio:

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

veloce

È abbastanza facile ottenere un conteggio del numero totale di istanze di un'entità in Dati principali:

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

Ho provato questo nel simulatore con un conteggio di oltre 400.000 oggetti e il risultato è stato abbastanza veloce (anche se non istantaneo).


23

Lo aggiungerò solo per renderlo ancora più efficiente ... e poiché è solo un conteggio, non hai davvero bisogno di alcun valore di proprietà e sicuramente come uno degli esempi di codice sopra non hai nemmeno bisogno di sub-entità.

Quindi, il codice dovrebbe essere così:

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;
}

Spero che sia d'aiuto.


10

Credo che il modo più semplice ed efficiente per contare gli oggetti sia impostare il NSFetchRequesttipo di risultato NSCountResultTypeed eseguirlo con il NSManagedObjectContext countForFetchRequest:error:metodo.

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

Ho scritto un semplice metodo di utilità per Swift 3 per recuperare il conteggio degli oggetti.

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

È davvero solo questo:

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

"Boat" è solo il nome dell'entità dalla schermata del modello dati:

inserisci qui la descrizione dell'immagine

Qual è il globale yourContainer?

Per utilizzare i dati di base, a un certo punto della tua app, una sola volta, vai semplicemente

var yourContainer = NSPersistentContainer(name: "stuff")

dove "stuff" è semplicemente il nome del file del modello di dati.

inserisci qui la descrizione dell'immagine

Avresti semplicemente un singleton per questo,

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)") }
        }
    }
}

Quindi da qualsiasi parte dell'app

core.container

è il tuo contenitore,

Quindi in pratica per ottenere il conteggio di qualsiasi entità, è giusto

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

0

Se vuoi trovare il conteggio per specifici recuperi previsti, credo che questo sia il modo migliore:

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

if(count > 0) {
NSLog(@"EXIST"); 
} else {
NSLog(@"NOT exist");
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.