Search code examples
swiftpredicateswiftdata

Swift #Predicate with function usage on the argument


Is it possible to use a #Predicate that part of its expression calls a function (trying to pass that predicate into a SwiftData Query):

func myPredicate(year: Int, month: Int) -> Predicate<MyObj> {
   #Predicate<MyObj> { obj in
     let components = Calendar.current.dateComponents([.year, .month], from: obj.date))
     return components.year == year && components.month == month
   }
}

In this case I'm getting an error that: Predicate body may only contain one expression. I tried moving it to another static function like so:

extension MyObj {
  static func checkDate(date: Date, year: Int, month: Month) {
    let components = Calendar.current.dateComponents([.year, .month], from: obj.date))
    return components.year == year && components.month == month
  }
}

but now I'm getting The checkDate function is not supported in this predicate

Is there a way to do it, other than storing the date as a separate year and month fields?

Thanks


Solution

  • You can not call a function from the predicate, there is a list of what operations you can use in the documentation

    Instead you can calculate a date interval from the given parameters and then use those date values in the predicate

    static func predicate(year: Int, month: Int) -> Predicate<MyObj> {
        let minDate = Calendar.current.date(from: DateComponents(year: year, month: month))!
        let maxDate = Calendar.current.date(byAdding: .month, value: 1, to: minDate)!
    
        return #Predicate<MyObj> { object in
            object.date >= minDate && object.date < maxDate
        }
    }
    

    (I am force unwrapping the calculated dates here but depending on how the input values has been validated you might want some better error handling)