译自 www.hackingwithswift.com/books/ios-s…
更多内容,欢迎关注公众号 「Swift花园」
喜欢文章?不如来个 🔺💛➕三连?关注专栏,关注我 🚀🚀🚀
使用 NSPredicate 过滤 @FetchRequest
在使用 SwiftUI 的@FetchRequest属性包装器时,我们可以提供一个排序描述符的数组,用于控制结果的顺序,同时我们还可以提供一个NSPredicate来控制哪些结果应该被显示。Predicate,即谓词,是简单的测试,这个测试会被应用到我们的 Core Data 实体中的每个对象 —— 只有通过测试的对象才会被放进结果数组。
NSPredicate 的语法并不算好猜,但实际上你也只需要少数几种 predicate,因此情况不算太糟。
为了体验谓词,让我们创建一个叫 Ship 的实体,包含两个字符串书写:“name” 和 “universe”。
然后把 ContentView.swift 改成下面这样:
import CoreData
import SwiftUI
struct ContentView: View {
@Environment(\.managedObjectContext) var moc
@FetchRequest(entity: Ship.entity(), sortDescriptors: [], predicate: nil) var ships: FetchedResults<Ship>
var body: some View {
VStack {
List(ships, id: \.self) { ship in
Text(ship.name ?? "Unknown name")
}
Button("Add Examples") {
let ship1 = Ship(context: self.moc)
ship1.name = "Enterprise"
ship1.universe = "Star Trek"
let ship2 = Ship(context: self.moc)
ship2.name = "Defiant"
ship2.universe = "Star Trek"
let ship3 = Ship(context: self.moc)
ship3.name = "Millennium Falcon"
ship3.universe = "Star Wars"
let ship4 = Ship(context: self.moc)
ship4.name = "Executor"
ship4.universe = "Star Wars"
try? self.moc.save()
}
}
}
}然后点击按钮注入一些范例数据到 Core Data,不过目前我们还没有应用谓词。为了解决这个问题,我们要把谓词参数的nil值替换成某种可以被应用给我们的对象的测试。
举个例子,我们可以要求飞船必须来自 Star Wars,像这样:
@FetchRequest(entity: Ship.entity(), sortDescriptors: [], predicate: NSPredicate(format: "universe == 'Star Wars'")) var ships: FetchedResults<Ship>如果你的数据包含引号,那么像上面的写法就会带来麻烦。所以通常我们会用特殊语法代替:%@表示“在这里插入某些数据”,可以让我们以参数而不是内联的方式书写谓词。
所以,把 predicate 写法改成这样:
NSPredicate(format: "universe == %@", "Star Wars"))不仅可以用==,我们还可以用诸如<和>这样的比较来过滤对象。例如,下面的例子会返回 Defiant, Enterprise 和 Executor:
NSPredicate(format: "name < %@", "F")) var ships: FetchedResults<Ship>%@在幕后做了大量的工作,特别是把原生 Swift 类型转换成它们对应的 Core Data 类型。例如,我们可以用一个IN谓词来检查某个宇宙是否来自某个数组的三个选项之一,像这样:
NSPredicate(format: "universe IN %@", ["Aliens", "Firefly", "Star Trek"])我们还可以用一个谓词来检查一个字符串的部分,用诸如BEGINSWITH和CONTAINS这样的操作符。例如,下面的代码会返回所有以大写字母 E 开头的飞船:
NSPredicate(format: "name BEGINSWITH %@", "E"))谓词是大小写敏感的,如果你想忽略大小写,需要把代码改成下面这样:
NSPredicate(format: "name BEGINSWITH[c] %@", "e"))CONTAINS[c] 的工作方式类似,差异就在于你的子字符串可以出现在属性值的任何部分,而不仅是头部。
最后,你还可以用 NOT 来反转谓词,得到常规行为相反的结果。例如,下面的代码可以找出所有不以 E 开头的飞船:
NSPredicate(format: "NOT name BEGINSWITH[c] %@", "e"))如果你想要更复杂的谓词,可以用AND尽可能精确地组合它们,或者导入 Core Data,尝试一下NSCompoundPredicate—— 它能让你基于几个更小的谓词构建出一个大的谓词。
我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~