Cocoa Core Data efficient way to count entities

Viewed 63585

I read much about Core Data.. but what is an efficient way to make a count over an Entity-Type (like SQL can do with SELECT count(1) ...). Now I just solved this task with selecting all with NSFetchedResultsController and getting the count of the NSArray! I am sure this is not the best way...

10 Answers

I don't know whether using NSFetchedResultsController is the most efficient way to accomplish your goal (but it may be). The explicit code to get the count of entity instances is below:

// 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];

To be clear, you aren't counting entities, but instances of a particular entity. (To literally count the entities, ask the managed object model for the count of its entities.)

To count all the instances of a given entity without fetching all the data, the use -countForFetchRequest:.

For example:

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;

It's really just this:

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

"Boat" is just the name of the entity from your data model screen:

enter image description here

What is the global yourContainer?

To use core data, at some point in your app, one time only, you simply go

var yourContainer = NSPersistentContainer(name: "stuff")

where "stuff" is simply the name of the data model file.

enter image description here

You'd simply have a singleton for this,

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

So from anywhere in the app

core.container

is your container,

So in practice to get the count of any entity, it's just

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

Swift 5 solution:

        var viewContext: NSManagedObjectContext!
        do {
            let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "insertName")
            let count = try viewContext.count(for: fetchRequest)
            print("Counted \(count) objects")
        }
        catch {
            print("Error")
        }
Related