译自 https://www.hackingwithswift.com/books/ios-swiftui/dynamically-filtering-fetchrequest-with-swiftui
更多内容,欢迎关注公众号 「Swift花园」
喜欢文章?不如来个 ➕三连?关注专栏,关注我

在 SwiftUI 中动态过滤 @FetchRequest

对于 SwiftUI ,我经常被问到的一个问题是:我要怎么样动态地改变一个 Core Data@FetchRequest,以便使用不同的谓词或者排序呢?大家之所以会提出这个问题是因为 fetch 请求是作为属性被创建的,因此如果你尝试让它们引用另外的属性,会被 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"

对于视图的body,我们会用一个VStack包裹三个按钮,再加上一个放匹配的歌手列表的注释占位:

VStack {// list of matching singersButton("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"}
}

目前为止,一切都很简单,接下来是有趣的部分:我们需要替换掉// list of matching singers这个注释,用实际的实现代替。这里不会用到@FetchRequest注解,因为我们要在构造器里创建一个自定义 fetch 请求,但代码几乎是一样的。

创建一个叫 “FilteredList” 的 SwiftUI 视图,给它这个属性:

var fetchRequest: FetchRequest<Singer>

这个属性用来存储我们的 fetch 请求,以便我们可以在body里遍历它。不过,我们并不马上创建它,因为我们还不知道我们要找的是什么东西。相反,我们要创建一个自定义构造器,接收一个过滤字符串,然后用这个字符串来设置fetchRequest属性。

添加下面这个构造器:

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

这会得到一个用当前的托管对象上下文构建的 fetch 请求。因为这个视图会被用在ContentView内部,所以我们不必为其注入托管对象上下文到环境中 —— 它会继承来自ContentView的上下文。

剩下的事情就是完成视图的body,这里唯一有趣的事情是,没有了@FetchRequest,我们需要访问fetchRequestwrappedValue属性来拉出我们的数据。因此,视图的body实现如下:

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

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

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

至于FilteredList的预览,你可以直接移除。

这样一来视图就完成了,我们可以回到ContentView,把注释用实际的代码实现,如下:

FilteredList(filter: lastNameFilter)

运行应用尝试下:点击 Add Examples 按钮先创建三个歌手,然后点击 “Show A” 或者 “Show S” 来触发不同的姓氏过滤。你应该会看到列表随着你点击不同的按钮,动态更新不同的数据。

为了让这一切工作,用到一点新的知识,但算不上难 —— 只要你以 SwiftUI 的方式思考,答案会跃然纸上。


我的公众号 这里有Swift及计算机编程的相关文章,以及优秀国外文章翻译,欢迎关注~

xcode动态改变窗口大小_[SwiftUI 100天] 在 SwiftUI 中动态过滤 @FetchRequest相关推荐

  1. xcode动态改变窗口大小_详细的理论要点+3个经典案例,帮助你深入理解动态面板...

    什么是动态面板 动态面板是Axure的高级交互元件,由不同的状态面板组成,是我们制作交互过程中运用频率最高的元件,很多交互效果需要依赖动态面板实现.动态面板的状态面板就像是一个容器,我们可以在里面放置 ...

  2. Electron无边框窗口(最小化、最大化、关闭、拖动)以及动态改变窗口大小

    文章目录 一.目标原型 1. 目标 2. 原型设计 3. 原型初步实现 二.无边框窗口 1. 要点 2. 改造 三.可拖拽区 1. 要点 2. 改造 四.最小化.最大化.关闭 1. 要点 2. 改造 ...

  3. 动态改变标题_插入控件-gt;引用变量-gt;实现动态图表纵横筛选

    欢迎关注我的微信公众号:HR爱玩儿Excel和PPT,分享有趣又有逼格的Excel和PPT创意和技巧,emmm...不关注也没有关系...哼 昨晚没睡好,因为睡前老友跟我说了句话: 我们总部做的表没有 ...

  4. tablayout 动态改变标题_描点法画函数图像的动态演示——动态数学软件GeoGebra制作教程...

    描点法画函数图像的步骤有: 列表 描点 连线 本文以制作一次函数 y=kx+b (k≠0)为例,先看效果: 觉得还不错的话,一起动手制作吧! 制作前 由于多个滑动条需设置为"递增(一次)&q ...

  5. 动态改变标题_小米相册更新,新增动态换天/赛博朋克/MIUI12界面等等!

    嗨咯,各位小伙伴们大家晚上好呀,今天为大家介绍一款灰度测试应用"MIUI相册"也就是大家小米手机里面的相册app,为方便解说,以下统称为"相册"更新后打开相册第 ...

  6. 动态改变类名_反调试之检测类名与标题名

    本文内容分为两部分: 1.介绍涉及到的API 2.实践 涉及到的API函数的学习: 1.GetProcAddress 定义:GetProcAddress是一个计算机函数,功能是检索指定的动态链接库(D ...

  7. jq动态改变路径_在react中使用jQuery动态更改图片路径遇到的问题

    您好.如题.我在代码中是这样写的. step:1 为了将默认的小图片列表从上方移到左边,我设置了template Viewer.TEMPLATE = ( ' ' + ' ' ' + ' ' ' + ' ...

  8. java按钮改变窗口大小_布局似乎有问题,JButton在调整窗口大小时显示出意外的行为。...

    很好的例子的问题可能与平台有关,但我可以提供一些观察:您没有添加或删除组件,所以您不需要revalidate(). 由于背景色是按钮的绑定属性,因此不需要后续调用repaint(). 你,你们做需要r ...

  9. javascript动态改变窗口大小

    var w = document.body.offsetWidth ; var h = document.body.offsetHeight  + 20; self.resizeTo(w,h); 转载 ...

  10. unity图片变成马赛克如何取像素并改变颜色_聊聊 2D 游戏的像素化中的问题

    来indienova官网,挖掘独立游戏的更多乐趣 引言 既然我是在做像素游戏,这次就聊一聊在对 2D 游戏像素化的过程中都会碰到的问题吧. 1. 照相机的投影 对于引擎来说,其实不管是 2D 游戏还是 ...

最新文章

  1. python中ttk和tkinter_Python tkinter与ttk日历
  2. 见到了“公司”定义一个Company类,那么见到了“字段”是不是也可定义一个Column类?...
  3. 12JavaScript中的内置对象
  4. 4.2 深层网络中的前向传播-深度学习-Stanford吴恩达教授
  5. Asp.Net数据库编程-10条最优方法[翻译]
  6. 计算机网络(谢希仁第八版)第一章:概述
  7. SmartNews:基于 Flink 加速 Hive 日表生产的实践
  8. [图]罗技推出背光键盘
  9. python是干什么用的-python是做什么用的 python有什么用 - 驱动管家
  10. Android - 资源(resource)转换为String
  11. 初识B/S结构编程技术
  12. 做Meta分析要用哪些软件?Meta分析软件盘点,含软件安装包!
  13. svn命令行回滚到指定版本
  14. URI和URL、URN的作用和区别
  15. 分享Canvas画横断面图的vue源码
  16. egret引擎p2物理引擎(2) - 小球碰撞地面搞笑的物理现象
  17. 9、智能化WebUI自动化测试框架recheck-web实战
  18. AD9361参数设置总结
  19. postman获取返回值及tests[]用法
  20. 屏幕录制方法?如何在电脑进行屏幕录制

热门文章

  1. 【知了堂学习笔记】$.ajax配合Servlet实现登录验证
  2. mac使用php-version切换PHP版本
  3. 从源码理解Bean的生命周期执行顺序
  4. MySQL5.7的下载以及安装
  5. 设计模式 (十四) Cglib动态代理模式
  6. 苏三30篇原创高质量文章汇总
  7. 隔壁小孩也能看懂的面向对象(概念篇)
  8. BS与CS的联系与区别【简】
  9. LINUX修改文件权限
  10. 运行出现 Multiple dex files define Landroid/support/annotation/AnimRes 解决方法