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 的数据过滤功能。

相关推荐
小洋人最happy2 天前
SwiftUI基础组件之HStack、VStack、ZStack详解
swiftui·vstack·zstack·hstack·spacing
coooliang2 天前
【iOS】SwiftUI状态管理
ios·swiftui·swift
小洋人最happy3 天前
SwiftUI基础组件之List详解
list·swiftui·selection·列表组件·ondelete
struggle20255 天前
Ollmao (OH-luh-毛程序包及源码) 是一款原生 SwiftUI 应用程序,它与 Ollama 集成,可在 Mac 上本地运行强大的 AI 模型
ios·swiftui·swift
货拉拉技术1 个月前
货拉拉用户端SwiftUI踩坑之旅
ios·swiftui·swift
ZacJi1 个月前
巧用 allowsHitTesting 自定义 SignInWithAppleButton
ios·swiftui·swift
刘争Stanley1 个月前
SwiftUI 是如何改变 iOS 开发游戏规则的?
ios·swiftui·swift
1024小神1 个月前
在swiftui中使用Alamofire发送请求获取github仓库里的txt文件内容并解析
ios·github·swiftui
大熊猫侯佩2 个月前
SwiftUI 撸码常见错误 2 例漫谈
swiftui·xcode·tag·tabview·preview·coredata·fetchrequest
东坡肘子2 个月前
肘子的 Swift 周报 #063|异种肾脏移植取得突破
swiftui·swift·apple