有没有办法在初始化后用谓词修改获取的结果?

Jan*_*nis 5 search predicate core-data swiftui

我正在尝试为现有的 CoreData 应用程序(简单的日志记录应用程序)构建搜索视图。我把所有存储与CoreData的数据和被提取与@FetchRequest

@State private var searchPredicate: NSPredicate? = NSPredicate(format: "title contains[c] %@", "")

@FetchRequest( entity: Item.entity(), sortDescriptors: [NSSortDescriptor(keyPath: \Item.title, ascending: true)],
      predicate: NSPredicate(format: "title contains[c] %@", "h")
    ) 
var items: FetchedResults<Item>
Run Code Online (Sandbox Code Playgroud)

它现在只获取通过谓词测试的项目,在这种情况下,这些项目都是包含“h”的项目。然后我将结果显示在 SearchView 主体的列表中:

List {

  ForEach(Items) { Item in

      ListViewItem(title: Item.title!, subTitle: Item.subTitle!, createdAt: "\(Item.createdAt!)")

     }
}
Run Code Online (Sandbox Code Playgroud)

然后我创建了一个新类“Searchbar”,它在搜索视图中被调用,它应该根据搜索字段的输入创建一个谓词,然后将它作为绑定传递给父级,然后基于该谓词正确的项目可以显示。

在搜索视图中调用 VStack 顶部的搜索栏:

SearchBar(text: $searchText, predicate: $searchPredicate)
Run Code Online (Sandbox Code Playgroud)

绑定会根据“searchBar”中的用户输入而变化:

func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {

    text = searchText
    predicate = NSPredicate(format: "title contains[c] %@", searchText)

 }
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好...

我现在遇到的问题是我们有一个有效的谓词,但不能在定义中的 @Fetchrequest 中调用,因为它会在初始化之前被调用。

@State private var searchPredicate: NSPredicate? = NSPredicate(format: "title contains[c] %@", "")


@FetchRequest(
    entity: Item.entity(),
    sortDescriptors: [
        NSSortDescriptor(keyPath: \Item.title, ascending: true)
    ],
    predicate: searchPredicate
) var items: FetchedResults<Item>
Run Code Online (Sandbox Code Playgroud)

这给了我一个错误,即在 self 可用之前无法运行属性初始值设定项,这是合乎逻辑的,但让我想知道并让我回到我的问题:有没有办法在初始化后用谓词修改获取的结果?

我还尝试在 ForEach() 语句中对获取的结果调用谓词相关的方法,但它们似乎都不起作用。

如果有任何问题,请随时提出。

Asp*_*eri 11

有没有办法在初始化后用谓词修改获取的结果?

嗯...不,不是你尝试这样做的方式,即使你尝试使用 NSFetchRequest 实例(它是引用)创建它,并允许稍后更改谓词,那也是行不通的,因为 SwiftUI 的 FetchRequest存储提供的获取请求的副本(或使用提供的参数创建自己的请求)...所以,不。但...

您可以将提供获取请求参数的视图与构建获取请求并显示结果的视图分开。

这是一个方法演示(它的重要部分),它使您可以通过不同的动态更改谓词获得结果:

struct MasterView: View {
    @State var predicate: NSPredicate? = nil
    var body: some View {
        VStack {
            Button(action: { // button just for demo
                self.predicate = NSPredicate(format: "title contains[c] %@", "h")
            }, label: { Text("Filter") })
            ResultView(predicate: self.predicate)
        }
    }
}

struct ResultView: View {

    @FetchRequest
    var events: FetchedResults<Event>

    @Environment(\.managedObjectContext)
    var viewContext

    init(predicate: NSPredicate?) {
        let request: NSFetchRequest<Event> = Event.fetchRequest()
        request.sortDescriptors = [NSSortDescriptor(keyPath: \Event.timestamp, ascending: true)]
        if let predicate = predicate {
            request.predicate = predicate
        }
        _events = FetchRequest<Event>(fetchRequest: request)
    }
    
    var body: some View {
        List {
            ForEach(events, id: \.self) { event in
    ...
Run Code Online (Sandbox Code Playgroud)