美文网首页Hacking with iOS: SwiftUI Edition
SwiftUI Core Data:动态过滤 @FetchReq

SwiftUI Core Data:动态过滤 @FetchReq

作者: 韦弦Zhy | 来源:发表于2020-05-29 18:36 被阅读0次

    \color{red}{\Large \mathbf{Hacking \quad with \quad iOS: SwiftUI \quad Edition}}

    {\Large \mathbf{Core \ Data}}

    Dynamically filtering @FetchRequest - 韦弦zhy

    我被问到的有一个SwiftUI问题比其他任何问题都多:如何动态更改Core Data @FetchRequest以使用其他谓词或排序顺序?出现问题是因为获取请求被创建为一个属性,因此,如果您尝试使它们引用另一个属性,Swift将拒绝。

    这里有一个简单的解决方案,通常回想起来很明显,因为它正是其他一切工作的原理:我们应该将想要的功能分解到一个单独的视图中,然后将值注入其中。

    我想用一些真实的代码来演示这一点,因此,我整理了一个最简单的示例:它将三个歌手添加到Core Data,然后使用两个按钮显示姓氏以A或S结尾的歌手。

    首先创建一个名为Singer的新Core Data实体,并为其指定两个字符串属性:“firstName”和“lastName”。使用数据模型检查器将其Codegen 更改为 Manual / None,然后转到 Editor 菜单,然后选择 Create NSManagedObject Subclass,这样我们就可以获取可以自定义的Singer类。

    Xcode为我们生成文件后,打开 Singer+CoreDataProperties.swift 并添加以下两个属性,这些属性使该类更易于在SwiftUI中使用:

    var wrappedFirstName: String {
        firstName ?? "Unknown"
    }
    
    var wrappedLastName: String {
        lastName ?? "Unknown"
    }
    

    好的,现在进入真正的工作。

    第一步是设计一个可容纳我们信息的视图。就像我说的那样,这还将有两个按钮,使我们可以更改视图过滤的方式,并且还将有一个额外的按钮来插入一些测试数据,以便您查看其工作方式。

    首先,向您的 ContentView 结构体添加两个属性,以便我们有一个可以将对象保存到的托管对象上下文,以及可以用作过滤器的某些状态:

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

    对于视图的主体,我们将使用带有三个按钮的VStack,并在注释中添加希望List显示匹配歌手的位置:

    VStack {
        // 匹配的歌手列表
    
        Button("添加示例") {
            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"
        }
    }
    

    到目前为止,非常容易。现在,对于有趣的部分:我们需要将// 匹配的歌手列表替换为真实的东西。这将不会使用@FetchRequest,因为我们希望能够在初始化程序中创建自定义提取请求,但是我们将使用的代码几乎相同。

    创建一个名为“FilteredList”的新SwiftUI视图,并为其提供以下属性:

    var fetchRequest: FetchRequest<Singer>
    

    这将存储我们的提取请求,以便我们可以在body内循环它。但是,由于我们仍然不知道要搜索的内容,因此我们不在此处创建提取请求。相反,我们将创建一个自定义初始化程序,该初始化程序接受过滤器字符串,并使用该字符串来设置fetchRequest属性。

    现在添加此初始化程序:

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

    这将使用当前的管理对象上下文运行获取请求。由于此视图将在ContentView中使用,因此我们甚至不需要将托管对象上下文注入到环境中——它将从ContentView继承上下文。

    剩下的就是编写视图主体,这里唯一有趣的是,如果没有@FetchRequest,我们需要读取fetchRequestwrappedValue属性以提取数据。因此,给出以下内容:

    var body: some View {
        List(fetchRequest.wrappedValue, id: \.self) { singer in
            Text("\(singer.wrappedFirstName) \(singer.wrappedLastName)")
        }
    }
    

    如果您不喜欢使用fetchRequest.wrappedValue,则可以创建一个简单的计算属性,如下所示:

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

    至于FilteredList的预览结构,可以安全地将其删除。

    现在,视图已完成,我们可以返回ContentView并将注释替换为将过滤器传递到FilteredList的一些实际代码:

    FilteredList(filter: lastNameFilter)
    

    现在运行该程序进行尝试:首先点击“添加示例”按钮以创建三个歌手对象,然后点击“Show A”或“ Show S”在姓氏字母之间切换。您应该看到我们的列表根据不同的数据动态更新,具体取决于您按的是哪个按钮。

    因此,这项工作需要一点新知识,但实际上并没有那么难——只要您像SwiftUI一样思考,解决方案就在那里。

    译自 Dynamically filtering @FetchRequest with SwiftUI

    相关文章

      网友评论

        本文标题:SwiftUI Core Data:动态过滤 @FetchReq

        本文链接:https://www.haomeiwen.com/subject/mfjgahtx.html