我正在尝试为现有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!)")
}
}
然后,我创建了一个新类“ Searchbar”,该类在searchview中被调用,并且应该基于搜索字段的输入来创建谓词,然后将其作为Binding传递给父项,然后基于该谓词可以显示正确的项目。
在搜索视图中调用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()语句中对获取的结果调用与谓词相关的方法,但似乎没有一个起作用。
如果有任何疑问,请不要犹豫。
答案 0 :(得分:0)
是否有一种方法可以在谓词之后用谓词修改获取的结果 初始化了吗?
好吧……不,不是您尝试执行此操作的方式,即使您尝试使用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
...
答案 1 :(得分:0)
由于我在其他任何地方都找不到可行的解决方案,因此我决定发布可能具有完整版本的Asperi做出的出色回答。
showDialog(
context: context,
builder: (_) => Container(
child: //add you custom widget here
));
}
还有SearchView:
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)
}
}
答案 2 :(得分:0)
作为对@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)