Какао Core Data эффективный способ подсчета объектов


174

Я много читал о Базовых Данных .. но что является эффективным способом подсчета по Entity-Type (как SQL может сделать с SELECT count (1) ...). Теперь я просто решил эту задачу, выбрав все с помощью NSFetchedResultsControllerи получив счет NSArray! Я уверен, что это не лучший способ ...

Ответы:


303

Я не знаю, является ли использование NSFetchedResultsController наиболее эффективным способом для достижения вашей цели (но это может быть). Явный код для получения количества экземпляров сущности приведен ниже:

// 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
На Leopard вы хотите использовать countForFetchRequest:, а не executeFetchRequest:
IlDan

И пропустите, чтобы установить предикат. Без предиката: получить все объекты, которые соответствуют описанию сущности
IlDan

4
Просто FYI, count == 0, если нет результатов для конкретного запроса, NSNotFound = NSIntegerMax, поэтому «// ошибка Генделя» не будет выполнена, если нет результатов.
Содержание

Есть ли опечатка на: setIncludeSubentities? Я думаю, что документация указывает на строчную букву «е» в «сущностях», а не прописную букву «Е» в примере кода.
Майк

2
@LarsSchneider - документация для countForFetchRequest:error:состояний, NSNotFoundвозвращаемая в случае ошибки. В общем, NSErrorобработка в соглашении Какао состоит в том, что значение errне определено (и часто опасно), если не происходит ошибка.
Барри Уарк

61

Чтобы было ясно, вы не учитываете сущности, но экземпляры конкретной сущности. (Чтобы буквально подсчитать объекты, попросите модель управляемого объекта подсчитать количество объектов.)

Для подсчета всех экземпляров данного объекта без извлечения всех данных используйте -countForFetchRequest:.

Например:

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

стриж

Довольно просто подсчитать общее количество экземпляров объекта в Базовых данных:

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

Я протестировал это в симуляторе с количеством объектов более 400 000, и результат был довольно быстрым (хотя и не мгновенным).


23

Я просто добавлю это, чтобы сделать его еще более эффективным ... и поскольку это всего лишь счет, вам не нужно никакого значения свойства и, конечно, как в приведенном выше примере кода, вам также не нужны дочерние объекты.

Итак, код должен быть таким:

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

Надеюсь, поможет.


10

Я считаю, что самый простой и эффективный способ подсчета объектов - установить NSFetchRequestтип результата NSCountResultTypeи выполнить его с помощью NSManagedObjectContext countForFetchRequest:error:метода.

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

Я написал простой служебный метод для Swift 3, чтобы получить количество объектов.

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

В Свифт 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

Это действительно так:

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

«Лодка» - это просто имя объекта на экране модели данных:

введите описание изображения здесь

Что такое глобальный yourContainer?

Чтобы использовать основные данные, в какой-то момент в вашем приложении, только один раз, вы просто идете

var yourContainer = NSPersistentContainer(name: "stuff")

где «материал» - это просто имя файла модели данных.

введите описание изображения здесь

У тебя просто есть синглтон для этого,

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

Так из любого места в приложении

core.container

твой контейнер,

Таким образом, на практике, чтобы подсчитать любую сущность, это просто

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

0

Если вы хотите найти число для конкретной предикатной выборки, я считаю, что это лучший способ:

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

if(count > 0) {
NSLog(@"EXIST"); 
} else {
NSLog(@"NOT exist");
}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.