Cacau Core Data maneira eficiente de contar entidades


174

Eu li muito sobre o Core Data ... mas qual é uma maneira eficiente de fazer uma contagem por um tipo de entidade (como o SQL pode fazer com o SELECT count (1) ...). Agora acabei de resolver esta tarefa selecionando todos com NSFetchedResultsControllere obtendo a contagem do NSArray! Tenho certeza de que essa não é a melhor maneira ...

Respostas:


303

Não sei se o uso de NSFetchedResultsController é a maneira mais eficiente de atingir seu objetivo (mas pode ser). O código explícito para obter a contagem de instâncias da entidade está abaixo:

// 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
No Leopard, você deseja usar countForFetchRequest: e não executeFetchRequest:
— IlDan

E pule para definir o predicado. Nenhum predicado: obter todos os objetos que correspondem à descrição entidade
— IlDan

4
Apenas para sua informação, conte == 0 se não houver resultados para a solicitação específica, NSNotFound = NSIntegerMax, portanto '// Erro de Handel' não será executado se não houver resultados.
— Intentss

Existe um erro de digitação em: setIncludesSubentities? Acho que a documentação indica uma letra minúscula "e" em "entidades" em vez da letra maiúscula "E" no código de exemplo.
— Mike

2
@LarsSchneider a documentação para os countForFetchRequest:error:estados NSNotFoundretornados em caso de erro. Em geral, o NSErrormanuseio na convenção de cacau é que o valor de erré indefinido (e geralmente perigoso) se nenhum erro ocorrer.
— Barry Wark

61

Para ser claro, você não está contando entidades, mas instâncias de uma entidade específica. (Para contar literalmente as entidades, solicite ao modelo de objeto gerenciado a contagem de suas entidades.)

Para contar todas as instâncias de uma determinada entidade sem buscar todos os dados, use -countForFetchRequest:.

Por exemplo:

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

Rápido

É bastante fácil obter uma contagem do número total de instâncias de uma entidade no Core Data:

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

Eu testei isso no simulador com uma contagem de mais de 400.000 objetos e o resultado foi bastante rápido (embora não instantâneo).


23

Vou acrescentar isso para torná-lo ainda mais eficiente ... e, como é apenas uma contagem, você realmente não precisa de nenhum valor de propriedade e, certamente, como um dos exemplos de código acima, também não precisa de subentidades.

Portanto, o código deve ser assim:

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

Espero que ajude.


10

Acredito que a maneira mais fácil e eficiente de contar objetos é definir o NSFetchRequesttipo de resultado NSCountResultTypee executá-lo com o NSManagedObjectContext countForFetchRequest:error:método

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

Eu escrevi um método utilitário simples para o Swift 3 buscar a contagem dos objetos.

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

Em 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

É realmente apenas isso:

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

"Barco" é apenas o nome da entidade na tela do seu modelo de dados:

insira a descrição da imagem aqui

O que é global yourContainer?

Para usar os dados principais, em algum momento do seu aplicativo, apenas uma vez, basta acessar

var yourContainer = NSPersistentContainer(name: "stuff")

onde "material" é simplesmente o nome do arquivo do modelo de dados.

insira a descrição da imagem aqui

Você simplesmente teria um singleton para isso,

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

Então, de qualquer lugar do aplicativo

core.container

é o seu contêiner,

Portanto, na prática, para obter a contagem de qualquer entidade, é apenas

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

0

Se você deseja encontrar a contagem para busca predicada específica, acredito que seja a melhor maneira:

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

if(count > 0) {
NSLog(@"EXIST"); 
} else {
NSLog(@"NOT exist");
}
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.