Swift Combine 使用 ObservableObject 与 SwiftUI 模型作为发布源 从入门到精通二十

Combine 系列

  1. Swift Combine 从入门到精通一
  2. Swift Combine 发布者订阅者操作者 从入门到精通二
  3. Swift Combine 管道 从入门到精通三
  4. Swift Combine 发布者publisher的生命周期 从入门到精通四
  5. Swift Combine 操作符operations和Subjects发布者的生命周期 从入门到精通五
  6. Swift Combine 订阅者Subscriber的生命周期 从入门到精通六
  7. Swift 使用 Combine 进行开发 从入门到精通七
  8. Swift 使用 Combine 管道和线程进行开发 从入门到精通八
  9. Swift Combine 使用 sink, assign 创建一个订阅者 从入门到精通九
  10. Swift Combine 使用 dataTaskPublisher 发起网络请求 从入门到精通十
  11. Swift Combine 用 Future 来封装异步请求 从入门到精通十一
  12. Swift Combine 有序的异步操作 从入门到精通十二
  13. Swift Combine 使用 flatMap 和 catch错误处理 从入门到精通十三
  14. Swift Combine 网络受限时从备用 URL 请求数据 从入门到精通十四
  15. Swift Combine 通过用户输入更新声明式 UI 从入门到精通十五
  16. Swift Combine 级联多个 UI 更新,包括网络请求 从入门到精通十六
  17. Swift Combine 合并多个管道以更新 UI 元素 从入门到精通十七
  18. Swift Combine 通过包装基于 delegate 的 API 创建重复发布者 从入门到精通十八
  19. Swift Combine 响应NotificationCenter 的更新 从入门到精通十九
    在这里插入图片描述

1. 和 SwiftUI 集成 使用 ObservableObject 与 SwiftUI 模型作为发布源

目的: SwiftUI 包含 @ObservedObjectObservableObject 协议,它为 SwiftUI 的视图提供了将状态外部化的手段,同时通知 SwiftUI 模型的变化。

SwiftUI 视图是基于某些已知状态呈现的声明性结构,当该状态发生变化时,这些当前的结构将失效并更新。 我们可以使用 Combine 来提供响应式更新来操纵此状态,并将其暴露回 SwiftUI。 此处提供的示例是一个简单的输入表单,目的是根据对两个字段的输入提供响应式和动态的反馈。

以下规则被编码到 Combine 的管道中:

  1. 两个字段必须相同 - 如输入密码或电子邮件地址,然后通过第二个条目进行确认。
  2. 输入的值至少为 5 个字符的长度。
  3. 根据这些规则的结果启用或禁用提交按钮。

SwiftUI 通过将状态外化为类中的属性,并使用 ObservableObject 协议将该类引用到模型中来实现此目的。 * 两个属性 firstEntrysecondEntry 作为字符串使用 @Published 属性包装,允许 SwiftUI 绑定到它们的更新,以及更新它们。

  • 第三个属性 submitAllowed 暴露为 Combine 发布者,可在视图内使用,从而维护视图内部的 @State buttonIsDisabled 状态
  • 第四个属性 —— 一个 validationMessages 字符串数组 - 在 Combine 管道中将前两个属性进行组合计算,并且使用 @Published 属性包装暴露给 SwiftUI。

SwiftUI-Notes/ReactiveFormModel.swift

import Foundation
import Combineclass ReactiveFormModel : ObservableObject {@Published var firstEntry: String = "" {didSet {firstEntryPublisher.send(self.firstEntry)  // 1}}private let firstEntryPublisher = CurrentValueSubject<String, Never>("")  // 2@Published var secondEntry: String = "" {didSet {secondEntryPublisher.send(self.secondEntry)}}private let secondEntryPublisher = CurrentValueSubject<String, Never>("")@Published var validationMessages = [String]()private var cancellableSet: Set<AnyCancellable> = []var submitAllowed: AnyPublisher<Bool, Never>init() {let validationPipeline = Publishers.CombineLatest(firstEntryPublisher, secondEntryPublisher)  // 3.map { (arg) -> [String] in  // 4var diagMsgs = [String]()let (value, value_repeat) = argif !(value_repeat == value) {diagMsgs.append("Values for fields must match.")}if (value.count < 5 || value_repeat.count < 5) {diagMsgs.append("Please enter values of at least 5 characters.")}return diagMsgs}submitAllowed = validationPipeline  // 5.map { stringArray inreturn stringArray.count < 1}.eraseToAnyPublisher()let _ = validationPipeline  // 6.assign(to: \.validationMessages, on: self).store(in: &cancellableSet)}
}
  1. firstEntrysecondEntry 都使用空字符串作为默认值。
  2. 然后,这些属性还用 currentValueSubject 进行镜像,该镜像属性使用来自每个 @Published 属性的 didSet 发送更新事件。这驱动下面定义的 Combine 管道,以便在值从 SwiftUI 视图更改时触发响应式更新。
  3. combineLatest 用于合并来自 firstEntrysecondEntry 的更新,以便从任一来源来触发更新。
  4. map 接受输入值并使用它们来确定和发布验证过的消息数组。该数据流 validationPipeline 是两个后续管道的发布源。
  5. 第一个后续管道使用验证过的消息数组来确定一个 truefalse 的布尔值发布者,用于启用或禁用提交按钮。
  6. 第二个后续管道接受验证过的消息数组,并更新持有的该 Observed在这里插入代码片Object 实例的 validationMessages,以便 SwiftUI 在需要时监听和使用它。

两种不同的状态更新的暴露方法 —— 作为发布者或外部状态,在示例中都进行了展示,以便于你可以更好的利用任一种方法。 提交按钮启用/禁用的选项可作为 @Published 属性进行暴露,验证消息的数组可作为 <String[], Never> 类型的发布者而对外暴露。 如果需要涉及作为显式状态去跟踪用户行为,则通过暴露 @Published 属性可能更清晰、不直接耦合,但任一种机制都是可以使用的。

上述模型与声明式地使用外部状态的 SwiftUI 视图相耦合。

SwiftUI-Notes/ReactiveForm.swift

import SwiftUIstruct ReactiveForm: View {@ObservedObject var model: ReactiveFormModel  // 1// $model is a ObservedObject<ExampleModel>.Wrapper// and $model.objectWillChange is a Binding<ObservableObjectPublisher>@State private var buttonIsDisabled = true  // 2// $buttonIsDisabled is a Binding<Bool>var body: some View {VStack {Text("Reactive Form").font(.headline)Form {TextField("first entry", text: $model.firstEntry)  // 3.textFieldStyle(RoundedBorderTextFieldStyle()).lineLimit(1).multilineTextAlignment(.center).padding()TextField("second entry", text: $model.secondEntry) // 4.textFieldStyle(RoundedBorderTextFieldStyle()).multilineTextAlignment(.center).padding()VStack {ForEach(model.validationMessages, id: \.self) { msg in  // 4Text(msg).foregroundColor(.red).font(.callout)}}}Button(action: {}) {Text("Submit")}.disabled(buttonIsDisabled).onReceive(model.submitAllowed) { submitAllowed in  // 5self.buttonIsDisabled = !submitAllowed}.padding().background(RoundedRectangle(cornerRadius: 10).stroke(Color.blue, lineWidth: 1))Spacer()}}
}struct ReactiveForm_Previews: PreviewProvider {static var previews: some View {ReactiveForm(model: ReactiveFormModel())}
}
  1. 数据模型使用 @ObservedObject 暴露给 SwiftUI。
  2. @State buttonIsDisabled 在该视图中被声明为局部变量,有一个默认值 true
  3. 属性包装($model.firstEntry$model.secondEntry) 的预计值用于将绑定传递到 TextField 视图元素。当用户更改值时,Binding 将触发引用模型上的更新,并让 SwiftUI 的组件知道,如果暴露的模型正在被更改,则组件的更改也即将发生。
  4. 在数据模型中生成和 assign 的验证消息,作为 Combine 管道的发布者,在这儿对于 SwiftUI 是不可见的。相反,这只能对这些被暴露的值的变化所引起的模型的变化做出反应,而不关心改变这些值的机制。
  5. 作为如何使用带有 onReceive 的发布者的示例,使用 onReceive 订阅者来监听引用模型中暴露的发布者。在这个例子中,我们接受值并把它们作为局部变量 @State 存储在 SwiftUI 的视图中,但它也可以在一些转化后使用,如果该逻辑只和视图显示的结果值强相关的话。在这,我们将其与 Button 上的 disabled 一起使用,使 SwiftUI 能够根据 @State 中存储的值启用或禁用该 UI 元素。

参考

https://heckj.github.io/swiftui-notes/index_zh-CN.html

代码

https://github.com/heckj/swiftui-notes

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/686179.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言系列(所需基础:大学C语言及格)-1-编译器/简单的求和代码/数据类型/变量的分类/变量的作用域和生命周期

文章目录 一、编译器&#xff08;使用在线编译器&#xff09;二、简单的求和代码三、数据类型四、变量的分类五、变量的作用域和生命周期 一、编译器&#xff08;使用在线编译器&#xff09; 为了方便&#xff0c;我使用的是在线的C语言编译器进行程序的运行。 链接&#xff1…

HTTP协议-响应报文详解(Respond)

目录 前言&#xff1a; 1.Respond报文 1.1报文格式 1.2格式图解 2.状态行&#xff08;首行&#xff09; 2.1状态码/状态码解释 &#xff08;1&#xff09;200 OK &#xff08;2&#xff09;404 Not Found &#xff08;3&#xff09;403 Forbidden &#xff08;4&#…

书生浦语大模型实战营-课程笔记(4)

微调分为两种&#xff0c;增量预训练和指令跟随。 指令跟随微调&#xff1a; 1.只对答案计算Loss 2.训练时数据为一问一答的形式&#xff08;input和output&#xff09; 增量预训练&#xff1a; 只需要output的数据进行训练 xtuner:微调框架 操作部分的笔记参考git上的文档…

模块、包、库的区别

这三者都是通过import和from…import…语句实现的。 模块&#xff08;module&#xff09; Python 模块(Module)&#xff0c;是一个 Python 文件&#xff0c;以 .py 结尾&#xff0c;包含了 Python 对象定义和Python语句。 简单来说任何一个以.py的文件都可以视为是一个模块(…

人工智能学习与实训笔记(六):神经网络之智能推荐系统

人工智能专栏文章汇总&#xff1a;人工智能学习专栏文章汇总-CSDN博客 本篇目录 七、智能推荐系统处理 7.1 常用的推荐系统算法 7.2 如何实现推荐 7.3 基于飞桨实现的电影推荐模型 7.3.1 电影数据类型 7.3.2 数据处理 7.3.4 数据读取器 7.3.4 网络构建 7.3.4.1用户特…

家庭动态网络怎么在公网访问主机数据?--DDNS配置(动态域名解析配置)

前言 Dynamic DNS是一个DNS服务。当您的设备IP地址被互联网服务提供商动态变更时,它提供选项来自动变更一个或多个DNS记录的IP地址。 此服务在技术术语上也被称作DDNS或是Dyn DNS 如果您没有一个静态IP,那么每次您重新连接到互联网是IP都会改变。为了避免每次IP变化时手动更…

使用C++,实现高精度加减乘除法运算!

我的个人主页 {\large \mathsf{{\color{Red} 我的个人主页} } } 我的个人主页 我的专栏&#xff1a; \mathcal{{\color{Green} 我的专栏&#xff1a;} } 我的专栏&#xff1a; 《精选文章》《算法》《每日一道编程题》《高精度算法》 文章目录 前言高精度计算初始模版string 转…

【Web】CTFSHOW java刷题记录(全)

目录 web279 web280 web281 web282 web283 web284 web285 web286 web287 web288 ​web289 web290 web291 web292 web293 web294 web295 web296 web297 web298 web299 web300 web279 题目提示 url里告诉我们是S2-001 直接进行一个exp的搜 S2-001漏洞分析…

【测试】测试用例篇

目 录 一. 设计测试用例的万能公式(六个)二.设计测试用例的具体方法1.等价类2.边界值3.因果图&#xff08;判定表&#xff09;4.场景设计法5.正交法6.错误猜测法 一. 设计测试用例的万能公式(六个) 设计测试用例的万能公式 测试用例的意义是帮助测试人员了解&#xff1a;测什…

linux 网络服务小实验

实验图和要求&#xff1a; 1&#xff09;网关服务器&#xff1a;ens36&#xff1a;12.0.0.254/24&#xff0c;ens33&#xff1a;192.168.44.254/24&#xff1b;Server1&#xff1a;192.168.44.20/24&#xff1b;PC1和Server2&#xff1a;自动获取IP&#xff1b;交换机无需配置。…

GEE:最小距离(minimumDistance)回归教程(样本点、特征添加、训练、精度、参数优化)

作者:CSDN @ _养乐多_ 对于分类问题,这个输出通常是一个类别标签 ,而对于回归问题,输出通常是一个连续的数值。回归可以应用于多种场景,包括预测土壤PH值、土壤有机碳、土壤水分、碳密度、生物量、气温、海冰厚度、不透水面积百分比、植被覆盖度等。 本文将介绍在Google…

频繁跳槽 可能问题出在你的性格上

谈到跳槽&#xff0c;小伙伴们会想到什么呢&#xff1f;换工作&#xff1f;涨薪&#xff1f;你有没有想过&#xff0c;目前的工作不合适&#xff0c;除了公司的原因&#xff0c;也有可能是自己性格的原因呢&#xff1f; 频繁跳槽有哪些优势和劣势呢&#xff1f;针对这些疑问&…

2024年【A特种设备相关管理(电梯)】找解析及A特种设备相关管理(电梯)模拟考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 A特种设备相关管理&#xff08;电梯&#xff09;找解析是安全生产模拟考试一点通生成的&#xff0c;A特种设备相关管理&#xff08;电梯&#xff09;证模拟考试题库是根据A特种设备相关管理&#xff08;电梯&#xff…

【STM32 CubeMX】I2C层次结构、I2C协议

文章目录 前言一、I2C的结构层次1.1 怎样在两个设备之间传输数据1.2 I2C如何传输数据1.3 硬件框图1.4 软件层次 二、IIC协议2.1 硬件连接2.2 I2C 总线的概念2.3 传输数据类比2.3 I2C信号2.4 I2C数据的含义 总结 前言 在STM32 CubeMX环境中&#xff0c;I2C&#xff08;Inter-In…

开年炸裂-Sora/Gemini

最新人工智能消息 谷歌的新 Gemini 模型 支持多达 1M的Token&#xff0c;可以分析长达一小时的视频 1M Token可能意味着分析700,000 个单词、 30,000 行代码或11 小时的音频、总结、改写和引用内容。 Comment&#xff1a;google公司有夸大的传统&#xff0c;所以真实效果需要上…

鸿蒙语言ArkTS(更好的生产力与性能)

ArkTS是鸿蒙生态的应用开发语言 ArkTS提供了声明式UI范式、状态管理支持等相应的能力&#xff0c;让开发者可以以更简洁、更自然的方式开发应用。 同时&#xff0c;它在保持TypeScript&#xff08;简称TS&#xff09;基本语法风格的基础上&#xff0c;进一步通过规范强化静态检…

qt-C++笔记之打印所有发生的事件

qt-C笔记之打印所有发生的事件 code review! 文章目录 qt-C笔记之打印所有发生的事件1.ChatGPT问答使用 QApplication 的 notify 方法使用 QObject 的 event 方法 2.使用 QObject 的 event 方法3.使用 QApplication 的 notify 方法 1.ChatGPT问答 在Qt C中&#xff0c;若要打…

老兵(11)

百度文心一格&#xff0c;大约是一年前上线并免费向用户开放的。其实也不是免费&#xff0c;而是“电量”比较好获得&#xff0c;白送的就16/每天&#xff0c;如果只是好奇玩玩的话也算够吧。 当时就很开心&#xff0c;因为一直想着把一些文案图像化&#xff0c;做成漫画的形式…

从被“大V”忽悠到自主开发投资分析系统:我在基金投资中的跌宕起伏与转变

从被“大V”忽悠到自主开发投资分析系统&#xff1a;我在基金投资中的跌宕起伏与转变 回顾我初次涉足基金投资的经历&#xff0c;那是一段由盲目跟从、亏损惨重到痛定思痛、自我提升的曲折历程。起初&#xff0c;我深受某些财经“大V”的影响&#xff0c;他们凭借看似精准的市…

算法刷题:复写零

复写零 .习题链接题目描述算法原理初始值步骤1步骤2我的答案: . 习题链接 复写零 题目描述 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素…