core-dataswiftuinsfetchrequest

Sum Double from filtered fetch request?


import SwiftUI
import Foundation
import CoreData

struct FilteredList: View {
    var fetchRequest: FetchRequest<FeedList>
    var value: FetchedResults<FeedList> {
        fetchRequest.wrappedValue
    }
    var total: Double = 0.0
    
    
    var body: some View {
        ForEach(value, id: \.self) {value in
            Text("Feed quantity is: \(value.feedquant.reduce(0) { $0 + $1.value}) ")
        }
    }
    
    init(filter: String) {
        fetchRequest = FetchRequest<FeedList>(entity:
           FeedList.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \FeedList.compdate, ascending: false)],
         predicate: NSPredicate(format: "compdate == %@", filter))
        
    }
    
}//: View

I have two attributes in my CoreData. Compdate stored as a String of a date and feedquant stored as a double. I am able to filter to get a fetch request of todays values through the init but I am unable to sum the attribute in a way that doesn't result in an error. Like above any attempt to sum in the view results in

Type '()' cannot conform to 'AccessibilityRotorContent'. -or- Type '()' does not conform to 'View"

So far no stackoverflow solution has worked for my case of summing an attribute in core data when having to filter by another attribute.


Solution

  • It seems that you have incorrectly written the code above. In your ForEach, you have a variable value which must be a collection (and I presume the result of your FetchRequest), but it is not defined anywhere. For the sake of this answer, I am going to assume that the first use of value is actually supposed to be singer.

    @Fogmeister is correct as to the problem you are having with regard to the error messages. You have to have a View and your code did not supply one. However, you remain with another, deeper problem with trying to use reduce()

    The problem you are having using reduce() is the way you have your CoreData model set up. You have an Entity entitled FeedList that has attributes of date and feedquant.

    When you get in to your ForEach, singer is a collection, but value is an individual managed object that is simply a String and a Double, but you have to use reduce on a collection, not a Double.

    You need to rethink your CoreData implementation. Personally, I would have two entities with a relationship. The first would be Date and the second would be FeedQuant. FeedQuant would have an attribute value which was a Double. I would then make a one to many relationship between Date and Feedquant. From Date I would call it hasFeedquant, and the inverse would be hasDate.

    Your FetchRequest would remain the same except the entity would be a Date entity, but now you would get a relationship hasFeedquant that is a collection, and you could then use reduce on that.

    Your code would then be:

    struct FilteredList: View {
      var fetchRequest: FetchRequest<FeedList>
      var feedDate: FetchedResults<Date> {
        fetchRequest.wrappedValue
      }
      var total: Double = 0.0
            
      var body: some View {            
        ForEach(feedDate, id: \.self) {value in
          // value.hasFeedquant is a Set<Feedquant> and so is reducible
          Text("Feed quantity is: \(value.hasFeedquant.reduce(0) { $0 + $1.value)") }
        }
      }
            
      init(filter: String) {
        fetchRequest = FetchRequest<Date>(
          entity: FeedList.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Date.compdate, ascending: false)],
          predicate: NSPredicate(format: "compdate == %@", filter)
        )        
      }
    } //: View