我有一个使用@FetchRequest从CoreData中显示对象的列表,我想为用户提供一个条形按钮,单击该按钮将过滤显示的列表。 如何更改@FetchRequest谓词并动态地重新运行它,以使用过滤后的项目重建列表?
struct EmployeeListView : View {
@FetchRequest(
entity: Department.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Department.name, ascending: false)],
)
var depts: FetchedResults<Department>
@Environment(\.managedObjectContext) var moc
var body: some View {
NavigationView {
List {
ForEach(depts, id: \.self) { dept in
Section(header: Text(dept.name)) {
ForEach(dept.employees, id: \.self) { emp in
Text(emp.name)
}
}
}
}
.navigationBarTitle("Employees")
}
}
}
我知道如何提供过滤器,我不知道如何更改属性包装器谓词并重新运行获取请求。
答案 0 :(得分:1)
您可以基于获取谓词中的绑定来更改结果,但是对于Bool var,我发现很难做到。原因是,在CoreData中测试Bool的谓词类似于NSPredicate(format: "myAttrib == YES")
,而您的Bool绑定变量将为true或false,而不是YES或NO ...因此,如果您NSPredicate(format: "%K ==%@", #keypath(Entity.seeMe), seeMe.wrappedValue)
,它将始终是假的。也许我错了,但这就是我所经历的。
您可以更容易地基于String数据过滤获取。但是,它的工作方式与下面的示例稍有不同,因为您需要像这样在View的init()中运行获取:
@Binding var searchTerm:String
var fetch: FetchRequest<Entity>
var rows: FetchedResults<Entity>{fetch.wrappedValue}
init(searchTerm:Binding<String>) {
self._searchTerm = searchTerm
self.fetch = FetchRequest(entity: Entity.entity(), sortDescriptors: [], predicate: NSPredicate(format: "%K == %@", #keyPath(Entity.attribute),searchTerm.wrappedValue))
}
要完成您描述的任务,请单击栏上的按钮项,从而切换布尔,下面是我建议的示例:
此示例将完成您的目标,而无需更改获取谓词。它使用逻辑来根据数据模型中的条目和@State变量的值来决定是否显示一行数据。
import SwiftUI
import CoreData
import Combine
struct ContentView: View {
@Environment(\.managedObjectContext) var viewContext
@State var seeMe = false
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Entity.attribute, ascending: true)],
animation: .default)
var rows: FetchedResults<Entity>
var body: some View {
NavigationView {
VStack {
ForEach(self.rows, id: \.self) { row in
Group() {
if (self.validate(seeMe: row.seeMe)) {
Text(row.attribute!)
}
}
}
.navigationBarItems(leading:
Button(action: {
self.seeMe.toggle()
}) {
Text("SeeMe")
}
)
Button(action: {
Entity.create(in: self.viewContext, attribute: "See Me item", seeMe: true)
}) {
Text("add seeMe item")
}
Button(action: {
Entity.create(in: self.viewContext, attribute: "Dont See Me item", seeMe: false)
}) {
Text("add NON seeMe item")
}
}
}
}
func validate(seeMe: Bool) -> Bool {
if (self.seeMe && seeMe) {
return true
} else if (!self.seeMe && !seeMe ){
return true
} else {
return false
}
}
}
extension Entity {
static func create(in managedObjectContext: NSManagedObjectContext,
attribute: String,
seeMe: Bool
){
let newEvent = self.init(context: managedObjectContext)
newEvent.attribute = attribute
newEvent.seeMe = seeMe
}
static func save(in managedObjectContext: NSManagedObjectContext) {
do {
try managedObjectContext.save()
} catch {
// Replace this implementation with code to handle the error appropriately.
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
let nserror = error as NSError
fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
}
}
}
要使用此示例,请创建一个核心数据模型,其中包含一个名为“ Entity”的实体和两个属性,一个名为“ attribute”的属性为String,另一个名为“ seeMe”的属性为Bool。然后运行它,按按钮创建两种类型的数据,然后单击顶部的条按钮项以选择要显示的数据。
我并不是最漂亮的示例,但是它应该演示您尝试完成的功能。
答案 1 :(得分:-1)
在提取请求上使用谓词来搜索具有特定名称的部门,例如:
struct ContentView: View {
@State var deptName = "Computing Science"
var body: some View {
EmployeeListView(name:deptName)
}
}
struct EmployeeListView : View {
@Environment(\.managedObjectContext) var managedObjectContext
@FetchRequest var depts : FetchedResults<Department>
init(name: name) {
_depts = FetchRequest(sortDescriptors: [NSSortDescriptor(keyPath: \Department.name, ascending: false)], predicate: NSPredicate(format: "name = %@", name)
}
var body: some View {
NavigationView {
List {
ForEach(depts) { dept in
Section(header: Text(dept.name)) {
ForEach(dept.employees, id: \.self) { emp in
Text(emp.name)
}
}
}
}
.navigationBarTitle("Employees")
}
}
}