Swift Combine 合并多个管道以更新 UI 元素 从入门到精通十七

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 更新,包括网络请求 从入门到精通十六
    在这里插入图片描述

1. 合并多个管道以更新 UI 元素

目的:观察并响应多个 UI 元素发送的值,并将更新的值联合起来以更新界面。

此示例故意模仿许多 Web 表单样式的验证场景,不过是在 UIKit 中使用 Combine。
在这里插入图片描述

ViewController 被配置了多个通过声明式更新的元素。 同时持有了 3 个主要的文本输入字段:

  • value1
  • value2
  • value2_repeat

它还有一个按钮来提交合并的值,以及两个 labels 来提供反馈。

这些字段的更新规则被实现为:

  • value1 中的条目至少有 3 个字符。
  • value2 中的条目至少有 5 个字符。
  • value2_repeat 中的条目必须与 value2 相同。

如果这些规则中的任何一个未得到满足,则我们希望禁用提交按钮并显示相关消息,解释需要满足的内容。

这可以通过设置连接与合并在一起的一系列管道来实现。

  • 有一个 @Published 属性匹配每个用户输入字段。 combineLatest 用于从属性中获取不断发布的更新,并将它们合并到单个管道中。 map 操作符强制执行所需字符和值必须相同的规则。 如果值与所需的输出不匹配,我们将在管道中传递 nil。
  • value1 还另外有一个验证管道,只使用了 map 操作符来验证值,或返回 nil。
  • 执行验证的 map 操作符内部的逻辑也用于更新用户界面中的 label 信息。
  • 最终管道使用 combineLatest 将两条验证管道合并为一条管道。 此组合的管道上连接了订阅者,以确定是否应启用提交按钮。

下面的示例将这些结合起来进行了展示。
UIKit-Combine/FormViewController.swift

import UIKit
import Combineclass FormViewController: UIViewController {@IBOutlet weak var value1_input: UITextField!@IBOutlet weak var value2_input: UITextField!@IBOutlet weak var value2_repeat_input: UITextField!@IBOutlet weak var submission_button: UIButton!@IBOutlet weak var value1_message_label: UILabel!@IBOutlet weak var value2_message_label: UILabel!@IBAction func value1_updated(_ sender: UITextField) {  // 1value1 = sender.text ?? ""}@IBAction func value2_updated(_ sender: UITextField) {value2 = sender.text ?? ""}@IBAction func value2_repeat_updated(_ sender: UITextField) {value2_repeat = sender.text ?? ""}@Published var value1: String = ""@Published var value2: String = ""@Published var value2_repeat: String = ""var validatedValue1: AnyPublisher<String?, Never> {  // 2return $value1.map { value1 inguard value1.count > 2 else {DispatchQueue.main.async {  // 3self.value1_message_label.text = "minimum of 3 characters required"}return nil}DispatchQueue.main.async {self.value1_message_label.text = ""}return value1}.eraseToAnyPublisher()}var validatedValue2: AnyPublisher<String?, Never> {  // 4return Publishers.CombineLatest($value2, $value2_repeat).receive(on: RunLoop.main)  // 5.map { value2, value2_repeat inguard value2_repeat == value2, value2.count > 4 else {self.value2_message_label.text = "values must match and have at least 5 characters"return nil}self.value2_message_label.text = ""return value2}.eraseToAnyPublisher()}var readyToSubmit: AnyPublisher<(String, String)?, Never> {  // 6return Publishers.CombineLatest(validatedValue2, validatedValue1).map { value2, value1 inguard let realValue2 = value2, let realValue1 = value1 else {return nil}return (realValue2, realValue1)}.eraseToAnyPublisher()}private var cancellableSet: Set<AnyCancellable> = []  // 7override func viewDidLoad() {super.viewDidLoad()self.readyToSubmit.map { $0 != nil }  // 8.receive(on: RunLoop.main).assign(to: \.isEnabled, on: submission_button).store(in: &cancellableSet)  // 9}
}
  1. 此代码的开头遵照了 通过用户输入更新声明式 UI 中的模式. IBAction 消息用于更新 @Published 属性,触发对所连接的任何订阅者的更新。
  2. 第一个验证管道使用 map 操作符接收字符串值输入,如果与验证规则不符,则将其转换为 nil。 这也将发布者属性的输出类型从 <String> 转换为可选的 <String?>。 同样的逻辑也用于触发消息文本的更新,以提供有关所需内容的信息。
  3. 由于我们正在更新用户界面元素,因此我们明确将这些更新包裹在 DispatchQueue.main.async 中,以在主线程上调用。
  4. combineLatest 将两个发布者合并到一个管道中,该管道的输出类型是每个上游发布者的合并值。 在这个例子中,输出类型是 (<String>, <String>) 的元组。
  5. 与其使用 DispatchQueue.main.async,不如使用 receive 操作符明确在主线程上执行下一个操作符,因为它将执行 UI 更新。
  6. 两条验证管道通过 combineLatest 相结合,并将经过检查的输出合并为单个元组输出。
  7. 我们可以将分配的管道存储为 AnyCancellable? 引用(将其映射到 viewcontroller 的生命周期),但另一种选择是创建一个变量来收集所有可取消的引用。 这从空集合开始,任何 sink 或 assign 的订阅者都可以被添加到其中,以持有对它们的引用,以便他们在 viewcontroller 的整个生命周期内运行。 如果你正在创建多个管道,这可能是保持对所有管道的引用的便捷方式。
  8. 如果任何值为 nil,则 map 操作符将向管道传递 false 值。 对 nil 值的检查提供了用于启用(或禁用)提交按钮的布尔值。
  9. store 方法可在 Cancellable 协议上调用,该协议明确设置为支持存储可用于取消管道的引用。在这里插入代码片

参考

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

代码

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

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

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

相关文章

centos中docker操作+安装配置django+mysql5.7并使用simpleui美化管理后台

一、安装docker 确保系统是CentOS 7并且内核版本高于3.10,可以通过uname -r命令查看内核版本。 更新系统软件包到最新版本,可以使用命令yum update -y。 安装必要的软件包,包括yum-utils、device-mapper-persistent-data和lvm2。使用命令yum install -y yum-utils devic…

软考 系统分析师系列知识点之信息系统战略规划方法(11)

接前一篇文章&#xff1a;软考 系统分析师系列知识点之信息系统战略规划方法&#xff08;10&#xff09; 所属章节&#xff1a; 第7章. 企业信息化战略与实施 第4节. 信息系统战略规划方法 7.4.7 价值链分析法 价值链分析&#xff08;Value Chain Analysis&#xff0c;VCA&am…

.NET Core MongoDB数据仓储和工作单元模式封装

前言 上一章我们把系统所需要的MongoDB集合设计好了&#xff0c;这一章我们的主要任务是使用.NET Core应用程序连接MongoDB并且封装MongoDB数据仓储和工作单元模式&#xff0c;因为本章内容涵盖的有点多关于仓储和工作单元的使用就放到下一章节中讲解了。仓储模式&#xff08;R…

两年前的爱爱竟然让她染上菜花和梅毒!医师警告:性病潜伏期不可小觑,HPV疫苗是必备的

【记者许家源/综合报道】 台北市一名30多岁的女性&#xff0c;因为私密处长出不明物体&#xff0c;到泌尿科求诊&#xff0c;没想到被诊断出是菜花&#xff0c;而且还合并了梅毒。 她回想起自己最后一次发生性关系&#xff0c;竟然是两年前和前男友的事&#xff0c;不明白为什…

搭建 blender python api 的外部开发环境

以下都是为了不直接在 blender 的 script ide 里写脚本而做&#xff0c;直接在 blender 里写的话就没什么参考意义了。 首先是2个blender的设置选项&#xff0c;建议开启&#xff0c;会比较方便。 开发选项启用后&#xff0c;你在一些菜单上右键的话&#xff0c;会多出来 在线…

CleanMyMac X2024版本有哪些常见的使用场景?

CleanMyMac X作为一款Mac电脑清理和优化工具&#xff0c;具有多种使用场景。以下是一些常见的使用场景&#xff1a; 清理系统垃圾文件&#xff1a;CleanMyMac X可以智能扫描Mac磁盘空间&#xff0c;清理系统冗余文件和各种软件应用产生的垃圾文件&#xff0c;如缓存、日志文件…

Kotlin基础——类、对象和接口

文章目录 1 定义类继承结构1.1 接口1.1.1 接口概述1.1.2 接口中的默认方法1.1.3 接口方法重复1.1.4 Kotlin接口中静态方法实现原理 1.2 修饰符1.2.1 类继承修饰1.2.2 方法重写修饰1.2.3 抽象类1.2.4 接口的修饰符 1.3 可见性修饰符1.3.1 Kotlin中的可见性修饰符1.3.2 Kotlin中的…

林浩然与杨凌芸的时空约会奇遇记

林浩然与杨凌芸的时空约会奇遇记 The Time-Traveling Love Story of Lin Haoran and Yang Lingyun in the Java World 在那个阳光明媚、Java代码飞舞的日子里&#xff0c;程序员界的“情圣”林浩然和美丽聪明的数据分析师杨凌芸携手演绎了一场跨越时间与空间的爱情故事&#xf…

ZYNQ:PL-CAN总线功能应用

流程背景 前期基本实现PS端的CAN总线功能&#xff0c;现阶段的主要目的是实现PL端的CAN总线功能&#xff0c;需要采用CAN IP。 PL系统搭建 PL外设时钟源 搭建完vivado系统后&#xff0c;需要在sdk编程。但是在配置PL&#xff0d;CAN时&#xff0c;意识到CAN时钟值不清楚&…

蓝桥省赛真题|简单:分数

题目链接&#xff1a;https://www.lanqiao.cn/problems/610/learning/?page1&first_category_id1&second_category_id3&tags2018&name%E5%88%86%E6%95%B0 题不难&#xff0c;但是可以帮助编程时好的习惯的养成&#xff0c;更加注意一些细节。 注意几个地方︰…

《区块链公链数据分析简易速速上手小册》第10章:未来趋势和挑战(2024 最新版)

文章目录 10.1 区块链技术的发展方向10.1.1 基础知识10.1.2 重点案例&#xff1a;构建一个简单的智能合约步骤1: 创建智能合约步骤2: 部署智能合约步骤3: 使用Python与智能合约交互结语 10.1.3 拓展案例 1&#xff1a;探索 DeFi 应用准备工作实现步骤步骤1: 获取Compound市场数…

Jmeter接口测试实战篇:10分钟学会Jmeter的用法

一提到接口测试&#xff0c;通常大家会有这样的疑问&#xff1a;前端测试不是已经覆盖到各种业务逻辑了吗&#xff1f;为什么还要做接口测试&#xff0c;接口测试和前端测试是不是重复了&#xff1f;对于这个问题&#xff0c;可以从下面几个方面来解释&#xff1a; 什么是接口…

CSS3学习(二)

目录&#xff1a; 1. 字体属性 1.1 字体系列 1.2 字体大小 1.3 字体粗细 1.4 文字样式 1.5 字体复合属性 1.6 总结 2 文本属性 2.1 文本颜色 2.2 对齐文本 2.3 装饰文本 2.4 文本缩进 2.5 行间距 2.6 总结 1. 字体属性 1.1 字体系列 使用font-family属性定义文…

Redis篇----第二篇

系列文章目录 文章目录 系列文章目录前言一、Memcache 与 Redis 的区别都有哪些?二、Redis 是单进程单线程的?三、一个字符串类型的值能存储最大容量是多少?四、Redis持久化机制前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点…

optee imx8mm

总仓库 git clone https://github.com/Xsyin/imx8mqevk.git -b container_region 替换imx8mqevk中的optee-client git clone https://github.com/nxp-imx/imx-optee-client.git -b lf-5.15.32_2.0.0 用 5.15.32 kernel 会有如下报错&#xff0c;需要将optee os升级到分支 lf-…

【开源】JAVA+Vue.js实现大学计算机课程管理平台

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 实验课程档案模块2.2 实验资源模块2.3 学生实验模块 三、系统设计3.1 用例设计3.2 数据库设计3.2.1 实验课程档案表3.2.2 实验资源表3.2.3 学生实验表 四、系统展示五、核心代码5.1 一键生成实验5.2 提交实验5.3 批阅实…

不同的AI修改同一篇文章标题

提问AI 我写了一篇文章&#xff0c;请帮我把标题重新改一下&#xff1a;“比较不同AI分析同一个错误代码及给出解决方案的能力&#xff08;结果出我意料&#xff09;” 这篇文章的原地址为&#xff1a;https://blog.csdn.net/snans/article/details/136132211 答案对比结果&am…

Qt:Qt3个窗口类的区别、VS与QT项目转换

一、Qt3个窗口类的区别 QMainWindow&#xff1a;包含菜单栏、工具栏、状态栏 QWidget&#xff1a;普通的一个窗口&#xff0c;什么也不包括 QDialog&#xff1a;对话框&#xff0c;常用来做登录窗口、弹出窗口&#xff08;例如设置页面&#xff09; QDialog实现简易登录界面…

网络原理-TCP_IP(6)

网络层 在复杂的网络环境中确定一个合适的路径. IP协议 与TCP协议并列,都是网络体系中最核心的协议. 基本概念 主机:配有IP地址,但是不进行路由控制的设备; 路由器:即配有IP地址,又能进行路由控制; 节点:主机和路由器的统称; 协议头格式 4位版本号(version):指定IP协议的版…

【机器学习基础】决策树(Decision Tree)

&#x1f680;个人主页&#xff1a;为梦而生~ 关注我一起学习吧&#xff01; &#x1f4a1;专栏&#xff1a;机器学习 欢迎订阅&#xff01;后面的内容会越来越有意思~ ⭐特别提醒&#xff1a;针对机器学习&#xff0c;特别开始专栏&#xff1a;机器学习python实战 欢迎订阅&am…