ios - SwiftUI 中的动态过滤器(谓词)

标签 ios swift xcode core-data swiftui

我正在使用 SwiftUI 和 CoreData 编写一个 iOS 应用程序。我现在正在努力解决一个问题几天。如何在 SwiftUI 中根据用户输入使用动态变化的谓词来制作动态过滤器?

我按照本教程学习了动态过滤器和 CoreData:https://www.hackingwithswift.com/quick-start/ios-swiftui/dynamically-filtering-fetchrequest-with-swiftui

经过一些小的更改后,我得到了以下代码。 ContentView.swift:

import SwiftUI

struct ContentView: View {

    @Environment(\.managedObjectContext) var moc
    @State var lastNameFilter = "A"

    var body: some View {

        VStack {
            FilteredList(predicate: lastNameFilter)

            Button("Add Examples") {
                let taylor = Singer(context: self.moc)
                taylor.firstName = "Taylor"
                taylor.lastName = "Swift"

                let ed = Singer(context: self.moc)
                ed.firstName = "Ed"
                ed.lastName = "Sheeran"

                let adele = Singer(context: self.moc)
                adele.firstName = "Adele"
                adele.lastName = "Adkins"

                try? self.moc.save()
            }

            Button("Show A") {
                self.lastNameFilter = "A"
            }

            Button("Show S") {
                self.lastNameFilter = "S"
            }
        }

    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

FilteredList.swift:

import CoreData
import SwiftUI

struct FilteredList: View {

    var predicate:String
    var fetchRequest: FetchRequest<Singer>
    var singers: FetchedResults<Singer>{fetchRequest.wrappedValue}

    var body: some View {
        List(singers, id: \.self) { singer in
            Text("\(singer.firstName ?? "Unknown") \(singer.lastName ?? "Unknown")")
        }
    }

    init(predicate: String) {
        self.predicate = predicate
        self.fetchRequest = FetchRequest<Singer>(entity: Singer.entity(), sortDescriptors: [], predicate: NSPredicate(format: "lastName BEGINSWITH %@", predicate))
    }

}

//struct FilteredList_Previews: PreviewProvider {
//    static var previews: some View {
//    }
//}

我还有 1 个名为 Singer 的实体,该实体有 2 个属性:firstNamelastName,这两个属性都是字符串。 上面的示例在模拟器中似乎运行良好,但在 Xcode 中使用预览时会导致应用程序崩溃。

我希望得到任何帮助,例如:

  • 指出要更改示例代码的哪一部分以避免预览中出现错误
  • 在 SwiftUI 中使用动态谓词的另一种方式的简单示例
  • 链接到有关 SwiftUI 中动态过滤器的教程

最佳答案

  1. 要使 ContentView 预览正常工作,您应该编写如下内容:
static var previews: some View {
    let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
    let taylor = Singer(context: context)
    taylor.firstName = "Taylor"
    taylor.lastName = "Swift"
    let ed = Singer(context: context)
    ed.firstName = "Ed"
    ed.lastName = "Sheeran"
    let adele = Singer(context: context)
    adele.firstName = "Adele"
    adele.lastName = "Adkins"
    return ContentView().environment(\.managedObjectContext, context)
}
  • 您可以实现更通用的 FilteredList 类型,其中仅提供列表的谓词(可选的排序描述符)。示例:
  • struct FilteredList<T: NSManagedObject, Content: View>: View {
        var fetchRequest: FetchRequest<T>
        var items: FetchedResults<T> { fetchRequest.wrappedValue }
    
        let content: (T) -> Content
    
        var body: some View {
            List(items, id: \.self) { item in
                self.content(item)
            }
        }
    
        init(predicate: NSPredicate?, sortDescriptors: [NSSortDescriptor] = [], @ViewBuilder content: @escaping (T) -> Content) {
            fetchRequest = FetchRequest<T>(entity: T.entity(), sortDescriptors: sortDescriptors, predicate: predicate)
            self.content = content
        }
    }
    

    将此新的 FilteredList 类型与 @State private var predicate: NSPredicate? 一起使用,而不是 @State var lastNameFilter = "A"。当需要新的过滤时,只需将此私有(private) @State 属性设置为新谓词,列表就会相应更新。

    具体用法是:

    FilteredList(predicate: predicate) { (singer: Singer) in
        Text("\(singer.firstName ?? "") \(singer.lastName ?? "")")
    }
    

    FilteredList 预览:

    static var previews: some View {
        FilteredList(predicate: nil) { (singer: Singer) in
            Text("\(singer.firstName ?? "") \(singer.lastName ?? "")")
        }.environment(\.managedObjectContext, (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext)
    }
    

    关于ios - SwiftUI 中的动态过滤器(谓词),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59501638/

    相关文章:

    objective-c - 什么是 _convertNSDictionaryToDictionary<A, B where ...> (NSDictionary?) -> [A : B] and why is it crashing my app?

    ios - 更新模型 Realm Swift

    objective-c - 将 Intruments 跟踪文件与 Xcode 项目连接起来

    ios - Xcode 11 向后兼容性 : "UIWindowScene is only available in iOS 13 or newer"

    ios - 在同一数据库上同时使用核心数据和基于 sqlite c 的 api

    ios - 以编程方式显示 iPhone 键盘

    ios - 在 UI TableView 单元格内单击获取图像

    xcode - 删除 heightForRowAtIndexPath : compatibility with iOs7

    ios - 当 View 从纵向更改为横向时,方向不会改变

    android - 无法从 Bloc Flutter 中听到新的值(value)