我正在尝试将类型的多个谓词与 and/or 组合起来。 以前使用 CoreData 和 NSPredicate 我只会这样做:
let predicate = NSPredicate(value: true)
let predicate2 = NSPredicate(value: false)
let combinedPred = NSCompoundPredicate(type: .or, subpredicates: [predicate, predicate2])
有没有类似的方法可以使用 SwiftData 和 #Predicate 来做到这一点? 如果没有,我如何实现一种预先创建部分条件并稍后将它们组合到谓词中的方法?
我发现将其作为表达式执行的唯一方法是这样的,但这将使我的谓词有数百行长
let includeOnlyFavorites = true
#Predicate { includeOnlyFavorites ? $0.isFavorite : true }
我正在开发一个应用程序,允许用户使用快捷操作保存和查询项目。这些项目使用 SwiftData 存储并使用 EntityPropertyQuery
进行查询Apple 是这样实现查询属性的:
static var properties = QueryProperties {
Property(\BookEntity.$title) {
EqualToComparator { NSPredicate(format: "title = %@", $0) }
ContainsComparator { NSPredicate(format: "title CONTAINS %@", $0) }
}
}
然后将谓词与
NSCompoundPredicate
组合起来。
返回布尔值的闭包:
let isFavorite = { (item: Item) in item.isFavorite }
let predicate = #Predicate<Item> { isFavorite($0) }
evaluate(Item) -> Bool
方法创建一个对象 IsFavoriteFilter 但我也无法使用它我还认为我可以在另一个谓词中使用 StandardPredicateExpression,因为在文档中它写道:
“组成谓词一部分的组件表达式,并且受标准谓词类型支持。” 但没有关于这种类型的进一步解释
哇。这很难,但我找到了解决问题的方法:
如果我们使用
PredicateExpression
而不是谓词,我们稍后可以构建如下谓词:
let expression = PredicateExpressions.Value(true)
let predicate = Predicate<String>({ input in
expression
})
下一步是注入输入。 我选择只创建一个接受变量并返回表达式的闭包(因为接受表达式的初始化程序不提供值,而是提供变量)
let variableExp = { (variable: PredicateExpressions.Variable<String>) in
let value = PredicateExpressions.Value("Hello There")
return PredicateExpressions.Equal(
lhs: variable,
rhs: value
)
}
let variablePredicate = Predicate<String>({ input in
variableExp(input)
})
Swift 数据模型:
@Model
class Book {
@Attribute
var title: String
@Attribute
var lastReadDate: Date
init(title: String, lastReadDate: Date) {
self.title = title
self.lastReadDate = lastReadDate
}
}
为我们要使用的表达式创建闭包。
typealias BookVariable = PredicateExpressions.Variable<Book>
typealias BookKeyPath<T> = PredicateExpressions.KeyPath<BookVariable,T>
let dateEquals = { (input: BookKeyPath<Date>, _ value: Date) in
return PredicateExpressions.Equal(
lhs: input,
rhs: PredicateExpressions.Value(value)
)
}
实际过滤:
// Do we want to filter by date at all?
let filterByDate = true
// The date we want to test against
let testDate = Date.now
let variablePredicate = Predicate<Book>({ input in
// Wrap values
let shouldFilterByDate = PredicateExpressions.Value(filterByDate)
let alwaysTrue = PredicateExpressions.Value(true)
// Create date Expression with testDate
let dateExp = dateEquals(BookKeyPath(root: input, keyPath: \Book.lastReadDate), testDate)
// Predicate that ,
// if shouldFilterByDate evaluates to true returns dateExp result
// otherwise returns expression that evaluates to true
return PredicateExpressions.build_Conditional(
shouldFilterByDate,
dateExp,
alwaysTrue
)
})