SwiftData 学习笔记:数据排序及数据过滤

前言

在上一篇文章中,我们介绍了 SwiftData 的增删改查的四种操作。这篇文章,我们将介绍一下如何对 SwiftData 进行数据排序以及数据过滤。

数据排序

如果想对查询的数据进行排序,最简单的方式就是使用 @Query 宏的额外选项。比如我们想让 Item 对象的数据以 name 进行排序,原始代码:

swift 复制代码
@Model
final class Item {
    var timestamp: Date
    var name: String
    
    init(timestamp: Date, name: String) {
        self.timestamp = timestamp
        self.name = name
    }
}

@Query private var items: [Item]

下面是以 name 属性进行正序排序的代码:

java 复制代码
@Query(sort: \Item.name)
private var items: [Item]

当然,我们也可以修改 order 参数的值,对数据以 name 属性进行逆向排序:

less 复制代码
@Query(sort: \Item.name, order: .reverse)

但是这种方式是有局限性的,那就是只能处理一个属性,如果你的需求是需要综合多个属性进行排序,比如对 Item 进行 name 的升序然后按 timestamp 进行降序。那么你需要使用 SortDescriptor 数组。

less 复制代码
@Query(sort: [SortDescriptor(\Item.name), SortDescriptor(\Item.timestamp, order: .reverse)])

需要注意的是,SortDescriptor 的使用是不会限制使用个数,所以你可以根据自己的需求添加任意个 SortDescriptor。 SwiftData 会根据添加顺序一个一个的去执行。

数据排序说完,接下来我们看一下如果对 SwiftData 进行数据过滤。

数据过滤

SwiftData 是通过谓词来进行数据过滤的:即通过测试是否符合条件来决定是否添加到返回的数组中。具体到代码方面,就是使用 #Predicate 宏来实现的。它会接受我们编写的 Swift 代码,将其转换为底层数据库可以识别的过滤器。

下面来看一下 #Predicate 在代码中,具体是怎么使用的。假设,当 name 的长度小于五位,我们就不显示该对象:

bash 复制代码
init(sort: SortDescriptor<Item>) {
    _items = Query(filter: #Predicate {
        $0.name.count > 5
    }, sort: [sort])
}

在上述代码中,我们给 #Predicate 传入了一个闭包,闭包的内容就是每个 item 对象的 name 长度需要大于五位。

在实际的 SwiftUI 项目中,如果我们需要实现根据用户的搜索来进行数据的过滤,则需要结合 searchable() 修饰符使用。

首先,我们需要声明一个属性用来接受用户输入的搜索文本:

java 复制代码
@State private var searchText = ""

接着,我们需要提供一个输入框,让用户输入想搜索的内容,这个使用 searchable() 修饰符实现:

php 复制代码
.searchable(text: $searchText)

然后,就是具体实现数据过滤的代码了,同样也是使用 #Predicate 宏来实现:

swift 复制代码
init(sort: SortDescriptor<Item>, searchString: String) {
    _items = Query(filter: #Predicate {
        if searchString.isEmpty {
            return true
        } else {
            return $0.name.localizedStandardContains(searchString)
        }
    }, sort: [sort])
}

Tips:一般来说,.localizedStandardContains() 是最好的方式用来实现用户的文本搜索。如果使用常规的 contains(),它是区分大小写的。

因为你改变了初始化方法,所以 #Preview 中的代码你也需要修改,否则编译是不通过的。因为是预览页面,所以 searchString 我们直接传递一个空字符串即可。

less 复制代码
#Preview {
    ItemListView(sort: SortDescriptor(\Item.name), searchString: "")
}

最后一步,因为我们是修改的 ItemListView 的代码,所以在创建 ItemListView 的时候我们也需要修改其初始化方法,然后将当前的 sortOrder 和搜索文本传递进去:

less 复制代码
ItemListView(sort: sortOrder, searchString: searchText)

这样,我们就实现了在 SwiftUI 页面中使用 SwiftData 的数据过滤功能。

相关推荐
传奇开心果编程10 小时前
【声明式UI开发实用技术学与练】第8课 状态提升与下放
学习·flutter·react native·ui·swiftui·composer
东坡肘子10 小时前
Swift Server,又多了一个 Google -- 肘子的 Swift 周报 #156
人工智能·swiftui·swift
传奇开心果编程1 天前
【现代声明式UI学与练】第4课 列表渲染与 key——如何高效渲染列表、key 的作用、列表重排时的状态保持
学习·flutter·react native·ui·swiftui·android jetpack
传奇开心果编程2 天前
【SwiftUI提高练中学】第8课 网络层架构:拦截器、重试、缓存与离线优先
学习·macos·ui·ios·swiftui
传奇开心果编程2 天前
【现代声明式UI学与练】第7课 组件通信——父传子、子传父、跨层级通信、状态提升与 Context
学习·flutter·react native·ui·swiftui·android jetpack
tink2 天前
告别 Xcode IDE:用 VS Code + SweetPad + XcodeGen 开发 iOS 应用的完整指南
ios·swiftui·xcode
传奇开心果编程2 天前
【现代声明式UI学与练】第9课 性能优化——渲染优化、列表优化、内存优化、启动优化
学习·flutter·react native·ui·性能优化·swiftui·android jetpack
传奇开心果编程5 天前
【现代声明式UI学与练】第1课 从命令式UI到声明式UI
学习·flutter·ui·swiftui·react·android jetpack
传奇开心果编程6 天前
【SwiftUI提高练中学】第13课 实时活动与灵动岛:ActivityKit 实战
学习·ui·ios·swiftui·swift
传奇开心果编程6 天前
【SwiftUI入门练中学】第17课 通知与后台任务
学习·ui·ios·swiftui·swift