swiftcore-datanspredicate

Multiple Fetches to count records from Core Data


I just want to share that I have a Core Data app with the following:

header bar

Each of them is a button where user can press to filter out the data for example (left to right): All, Inbox, Archive, More, Good, Evil, Important. You will also note that each of this button has a counter.

In my ViewModel, I have a function to count each of them, which is called when in the app's onAppear()

func countItem() -> (countTotal: Int, countArchive: Int, countGood: Int, countEvil: Int, countImportant: Int) {
    let request: NSFetchRequest<ThoughtEntity> = ThoughtEntity.fetchRequest()
    
    request.predicate = NSPredicate(format: "thoughts != %@", "")
    let items1 = (try? manager.container.viewContext.fetch(request)) ?? []
    let countTotalPredicate = items1.count
    
    request.predicate = NSPredicate(format: "isArchive == true")
    let items2 = (try? manager.container.viewContext.fetch(request)) ?? []
    let countArchivePredicate = items2.count
    
    request.predicate = NSPredicate(format: "type CONTAINS %@", "good")
    let items3 = (try? manager.container.viewContext.fetch(request)) ?? []
    let countGoodPredicate = items3.count
    
    request.predicate = NSPredicate(format: "type CONTAINS %@", "evil")
    let items4 = (try? manager.container.viewContext.fetch(request)) ?? []
    let countEvilPredicate = items4.count
    
    request.predicate = NSPredicate(format: "type CONTAINS %@", "important")
    let items5 = (try? manager.container.viewContext.fetch(request)) ?? []
    let countImportantPredicate = items5.count

    return (countTotalPredicate, countArchivePredicate, countGoodPredicate, countEvilPredicate, countImportantPredicate)
}

The code works well enough.

I am wondering is there a better way to do it instead of fetching it from the database 5 times? Perhaps the "cost" of fetching is low, so it doesn't matter but I am wondering if there is a better, more efficient way of doing it?


Solution

  • You can use the count(for:) method on the viewContext to return just the count, not all of the entities.

    let request: NSFetchRequest<ThoughtEntity> = ThoughtEntity.fetchRequest()
            
    request.predicate = NSPredicate(format: "thoughts != %@", "")
    let countTotalPredicate = try? manager.container.viewContext.count(for: request)) ?? 0