Can FetchedResultController track the change on sum of a certain property?

I wrote a simple IOS app tracking people daily calorie consumption. Every time they add a item they just consumed, a new object called “ItemConsumed” will generate in coreData, the class of it is like this:

extension ItemConsumed {
    @NSManaged var id: String?
    @NSManaged var name: String?
    @NSManaged var quantityConsumed: NSNumber?
    @NSManaged var totalCalories: NSNumber?
    @NSManaged var unitCalories: NSNumber?
    @NSManaged var quantity: String?
    @NSManaged var brand: String?
    @NSManaged var days: Day?
}

Then, in another TableViewController(static tableview), I was trying to do all the statistic work(total, avg etc.)

The first row calculates the total calories by far. That means add up all “totalCalories” in each object.(food1.totalCalories + food2.totalCalories + …)

I finished the app without FetchedResultController at first. But the drawback is: I have to put fetch function in viewWillAppear to make sure every time when users switch to this tableview(Since it is in tabBarController, ViewDidLoad only gets called once), they can get the most up-to-date result on total calories. That means: Even if there is no change on total calories at all(no new food added), I have to do the fetch regardless.

To avoid these, I tried FetchedResultController.

class StatisticTableViewController: UITableViewController{

    var fetchedResultsController: NSFetchedResultsController!
    var managedContext: NSManagedObjectContext!
    var totalCals: Double!
    @IBOutlet weak var FirstLineLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()
        fetchTotal()
        fetchedResultsController.delegate = self
        tableView.rowHeight = UITableViewAutomaticDimension
    }



     func fetchTotal(){
            let fetchRequest = NSFetchRequest(entityName: "ItemConsumed")
            fetchRequest.resultType = .DictionaryResultType
            let sortDes = NSSortDescriptor(key: "totalCalories", ascending: true)
            fetchRequest.sortDescriptors = [sortDes]
            let sumExpressionDesc = NSExpressionDescription()
            sumExpressionDesc.name = "Total"
            sumExpressionDesc.expression = NSExpression(forFunction: "sum:", arguments: [NSExpression(forKeyPath: "totalCalories")])
            sumExpressionDesc.expressionResultType = .DoubleAttributeType
            fetchRequest.propertiesToFetch = [sumExpressionDesc]

            fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: managedContext, sectionNameKeyPath: nil, cacheName: nil)

            do{
                try fetchedResultsController.performFetch()
                let results = fetchedResultsController.fetchedObjects as! [NSDictionary]
                let resultsDict = results.first!
                let total = resultsDict["Total"] as! Double
                totalCals = total
                FirstLineLabel.text = "\(totalCals)" + " Cal"
            }catch let error as NSError{
                print("Error: \(error.localizedDescription)")
            }
        }
}

extension StatisticTableViewController: NSFetchedResultsControllerDelegate{

        func controllerWillChangeContent(controller: NSFetchedResultsController) {
            tableView.beginUpdates()
        }

        func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) {
            switch type{
            case .Update:
                let results = fetchedResultsController.fetchedObjects as! [NSDictionary]
                let resultsDict = results.first!
                let total = resultsDict["Total"] as! Double
                totalCals = total
                FirstLineLabel.text = "\(totalCals)" + " Cal"
                print("updated")
            default: break
            }
        }

        func controllerDidChangeContent(controller: NSFetchedResultsController) {
            tableView.endUpdates()
        }
}

Got the Error: ‘NSFetchedResultsController does not support both change tracking and fetch request’s with NSDictionaryResultType’

The bigger question is: Can FetchedResultController deliver this kind job at all? Or is there an alternative approach that can also help avoid the drawback I mentioned above?

If FetchedResultController can do the job, then how do you set SortDescriptor(Required by fetchedResultController) when you get the sum of properties instead of a list of object as result?(I set the key as “totalCalories” in code above but i guess that is a mistake as well)

The bottom line is: I really don’t want to fetch every object out and do the sum calculation myself using a loop, since that could costs a lot of time and space when the number of objects get bigger.

Well you don’t need NSFRC to perform a fetch. You can perform a fetch manually just as you did above. Then you have to cycle through that dictionary and as you do, create a sum of just the key totalCalories.