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

Is there a way to modify fetched results with a predicate after they are initialized?

我正在尝试为现有的 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>

它现在只获取通过谓词测试的项目,在本例中是所有包含 "h" 的项目。 然后,我将结果显示在 SearchView 正文的列表中:

List {

  ForEach(Items) { Item in

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

     }
}

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

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

SearchBar(text: $searchText, predicate: $searchPredicate)

绑定根据 "searchBar" 中的用户输入而变化:

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

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

 }

到目前为止一切顺利...

我现在遇到的问题 运行 是我们有一个有效的谓词,但不能在定义中的 @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>

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

我也试过在 ForEach() 语句中对获取的结果调用谓词相关方法,但 none 似乎有效。

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

Is there a way to modify fetched results with a predicate after they are initialized?

嗯...不,不是以您尝试这样做的方式,即使您尝试使用 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
    ...

backup

我决定 post 使用 Asperi 提供的出色答案的完整工作版本,因为我在其他任何地方都找不到工作解决方案。

struct MasterView: View {


@State var predicate: NSPredicate? = nil

@State private var searchText = ""


var body: some View {

    VStack {


        TextField("Search", text: $searchText, onEditingChanged: {_ in


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

            print("THE PREDICATE: \(String(describing: self.predicate))")


            }, onCommit: {

             print("onCommit")

         }).foregroundColor(.primary)


        SearchView(predicate: self.predicate)

    }
}

}

和搜索视图:

struct SearchView: View {



@State private var searchText = ""

@Environment(\.managedObjectContext) var managedObjectContext



@FetchRequest var items: FetchedResults<Item>


init(predicate: NSPredicate?) {


    let request: NSFetchRequest<Item> = Item.fetchRequest() as! NSFetchRequest<Item>

    request.sortDescriptors = [NSSortDescriptor(keyPath: \Item.title, ascending: true)]

    if let predicate = predicate {

        request.predicate = predicate

    }

    _items = FetchRequest<Item>(fetchRequest: request)


}





var body: some View {


        VStack {



            List {
...

作为对@Asperi 回答(Swift 5.4 Xcode 12.5)的一点更新,您现在可以在 ResultView 中执行此操作:

var fetchRequest: FetchRequest<Event>

init(predicate: NSPredicate?) {
    fetchRequest = FetchRequest<Event>(entity: 
    Event.entity(), sortDescriptors: [NSSortDescriptor(keyPath: 
    \Event.timestamp, ascending: true)], predicate: predicate)
}

因为 FetchRequest 需要 NSPredicate?在其构造函数中:

public init(entity: NSEntityDescription, sortDescriptors: [NSSortDescriptor], predicate: NSPredicate? = nil, animation: Animation? = nil)