Swift Combine 发布者订阅者操作者 从入门到精通二

Combine 系列

  1. Swift Combine 从入门到精通一

1. Combine核心概念

你只需要了解几个核心概念,就能使用好 Combine,但理解它们非常重要。 这些概念中的每一个都通过通用协议反映在框架中,以将概念转化为预期的功能。

这些核心概念是:

  • Publisher and Subscriber
  • Operator 操作符
  • Subjects

2. Publisher and Subscriber

两个关键概念, publisher 和 subscriber,在 Swift 中被描述为协议。

当你谈论编程(尤其是 Swift 和 Combine)时,很多都使用类型描述。 当你说一个函数或方法返回一个值时,该值通常被描述为“此类型之一”。

Combine 就是定义随着时间的推移使用许多可能的值进行操作的过程。 Combine 还不仅仅是定义结果,它还定义了我们如何处理失败。 它不仅讨论可以返回的类型,还讨论可能发生的失败。

2.1 Publisher 发布者

现在我们要引入的第一个核心概念是发布者。 当其被订阅之后,根据请求会提供数据, 没有任何订阅请求的发布者不会提供任何数据。 当你描述一个 Combine 的发布者时,应该用两种相关的类型来描述它:一种用于输出,一种用于失败。

在这里插入图片描述
这些通常使用泛型语法编写,该语法在描述类型的文本周围使用 <> 符号。 这表示我们正在谈论这种类型的值的通用实例。 例如,如果发布者返回了一个 String 类型的实例,并且可能以 URLError 实例的形式返回失败,那么发布者可能会用 <String, URLError> 来描述。

2.2 订阅者 Subscriber

与发布者匹配的对应概念是订阅者,是第二个要介绍的核心概念。

订阅者负责请求数据并接受发布者提供的数据(和可能的失败)。 订阅者同样被描述为两种关联类型,一种用于输入,一种用于失败。 订阅者发起数据请求,并控制它接收的数据量。 它可以被认为是在 Combine 中起“驱动作用”的,因为如果没有订阅者,其他组件将保持闲置状态,没有数据会流动起来。

发布者和订阅者是相互连接的,它们构成了 Combine 的核心。 当你将订阅者连接到发布者时,两种类型都必须匹配:发布者的输出和订阅者的输入以及它们的失败类型。 将其可视化的一种方法是对两种类型进行一系列并行操作,其中两种类型都需要匹配才能将组件插入在一起。

在这里插入图片描述

2.3 操作符 Operator

第三个核心概念是操作符——一个既像订阅者又像发布者的对象。 操作符是同时实现了 订阅者协议 和 发布者协议 的类。 它们支持订阅发布者,并将结果发送给任何订阅者。

你可以用这些创建成链,用于处理和转换发布者提供的数据和订阅者请求的数据。

我称这些组合序列为管道。
在这里插入图片描述
操作符可用于转换值或类型 - 输出和失败类型都可以。 操作符还可以拆分或复制流,或将流合并在一起。 操作符必须始终按输出/失败这样的类型组合对齐。 编译器将强制执行匹配类型,因此类型错误将导致编译器错误(如果幸运的话,会有一个有用的 fixit 片段建议给你解决方案)。

用 swift 编写的简单的 Combine 管道如下所示:

let _ = Just(5) .map { value -> String in // do something with the incoming value here// and return a stringreturn "a string"}.sink { receivedValue in // sink is the subscriber and terminates the pipelineprint("The end result was \(receivedValue)")}
  1. 管道从发布者 Just 开始,它用它定义的值(在本例中为整数 5)进行响应。输出类型为 <Integer>,失败类型为 <Never>
  2. 然后管道有一个 map 操作符,它在转换值及其类型。 在此示例中,它忽略了发布者发出的输入并返回了一个字符串。 这也将输出类型转换为 <String>,并将失败类型仍然保持为 <Never>
  3. 然后管道以 sink 订阅者结束。

当你去尝试理解管道时,你可以将其视为由输出和失败类型链接的一系列操作。 当你开始构建自己的管道时,这种模式就会派上用场。 创建管道时,你可以选择操作符来帮助你转换数据、类型或两者同时使用以实现最终目的。 最终目标可能是启用或禁用用户界面的某个元素,或者可能是得到某些数据用来显示。 许多 Combine 的操作符专门设计用来做这些转换。

有许多操作符是以 try 为前缀的,这表示它们返回一个 <Error> 的失败类型。 例如 maptryMapmap 操作符可以转换输出和失败类型的任意组合。 tryMap 接受任何输入和失败类型,并允许输出任何类型,但始终会输出 <Error> 的失败类型。

map 这样的操作符,你在定义返回的输出类型时,允许你基于提供给操作符的闭包中返回的内容推断输出类型。 在上面的例子中,map 操作符返回一个 String 的输出类型,因为这正是闭包返回的类型。

为了更具体地说明更改类型的示例,我们扩展了值在传输过程中的转换逻辑。此示例仍然以提供类型 <Int, Never> 的发布者开始,并以类型为 <String, Never> 的订阅结束。
SwiftUI-NotesTests/CombinePatternTests.swift

let _ = Just(5) .map { value -> String in switch value {case _ where value < 1:return "none"case _ where value == 1:return "one"case _ where value == 2:return "couple"case _ where value == 3:return "few"case _ where value > 8:return "many"default:return "some"}}.sink { receivedValue in print("The end result was \(receivedValue)")}
  1. Just 是创建一个 <Int, Never> 类型组合的发布者,提供单个值然后完成。
  2. 提供给 .map() 函数的闭包接受一个 <Int> 并将其转换为一个 <String>。由于 <Never> 的失败类型没有被改变,所以就直接输出了。
  3. sink 作为订阅者,接受 <String, Never> 类型的组合数据。

当你在 Xcode 中创建管道,类型不匹配时,Xcode 中的错误消息可能包含一个有用的修复建议 fixit。 在某些情况下,例如上个例子,当提供给 map 的闭包中不指定特定的返回类型时,编译器就无法推断其返回值类型。 Xcode (11 beta 2 and beta 3) 显示此为错误消息: Unable to infer complex closure return type; add explicit type to disambiguate。 在上面示例中,我们用 value → String in 明确指定了返回的类型。

你可以将 Combine 的发布者、操作符和订阅者视为具有两种需要对齐的平行类型 —— 一种用于成功的有用值,另一种用于错误处理。 设计管道时经常会选择如何转换其中一种或两种类型以及与之相关的数据。

参考

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

代码

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

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

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

相关文章

Peter算法小课堂—区间模型

Peter Pan来啦…… 最大不重叠区间数 二话不说&#xff0c;先来一道题 大家想想怎么贪心&#xff1f;我们可以将每一个美食摊位抽象成一个区间&#xff0c;区间左端点为开始排队时间&#xff0c;右端点为结束排队时间。其中&#xff0c;时间信息可以用数轴表示。 额……我们…

Linux第49步_移植ST公司的linux内核第1步_获取linux源码

已知ST公司的linux源码路径&#xff1a; /home/zgq/linux/atk-mp1/stm32mp1-openstlinux-5.4-dunfell-mp1-20-06-24/sources/arm-ostl-linux-gnueabi/linux-stm32mp-5.4.31-r0 1、创建“my_linux”目录 打开第1个终端 输入“ls回车” 输入“cd linux/回车”&#xff0c;切换…

分享87个jQuery特效,总有一款适合您

分享87个jQuery特效&#xff0c;总有一款适合您 87个jQuery特效下载链接&#xff1a;https://pan.baidu.com/s/1H9kH2qrL-AHFn3jDlNvTFw?pwd8888 提取码&#xff1a;8888 Python采集代码下载链接&#xff1a;采集代码.zip - 蓝奏云 学习知识费力气&#xff0c;收集整理…

C#,数值计算,矩阵的行列式(Determinant)、伴随矩阵(Adjoint)与逆矩阵(Inverse)的算法与源代码

本文发布矩阵&#xff08;Matrix&#xff09;的一些初级算法。 一、矩阵的行列式&#xff08;Determinant&#xff09; 矩阵行列式是指矩阵的全部元素构成的行列式&#xff0c;设A(a)是数域P上的一个n阶矩阵&#xff0c;则所有A(a)中的元素组成的行列式称为矩阵A的行列式&…

2024春晚纸牌魔术原理----环形链表的约瑟夫问题

一.题目及剖析 https://www.nowcoder.com/practice/41c399fdb6004b31a6cbb047c641ed8a?tabnote 这道题涉及到数学原理,有一般公式,但我们先不用公式,看看如何用链表模拟出这一过程 二.思路引入 思路很简单,就试创建一个单向循环链表,然后模拟报数,删去对应的节点 三.代码引…

【SpringBoot】Validator组件+自定义约束注解实现手机号码校验和密码格式限制

&#x1f3e1;浩泽学编程&#xff1a;个人主页 &#x1f525; 推荐专栏&#xff1a;《深入浅出SpringBoot》《java对AI的调用开发》 《RabbitMQ》《Spring》《SpringMVC》 &#x1f6f8;学无止境&#xff0c;不骄不躁&#xff0c;知行合一 文章目录 前言一、Cons…

超越‘赞’按钮:Facebook情感智能的突破之路

社交媒体已经成为了我们生活中不可或缺的一部分。我们通过它与朋友、家人和同事保持联系&#xff0c;分享快乐和悲伤&#xff0c;表达意见和观点。然而&#xff0c;长期以来&#xff0c;我们只能通过简单的“赞”按钮来回应他人的帖子。这种单一的反馈方式无法真正展现我们复杂…

【Tauri】(2):使用Tauri应用开发,使用开源的Chatgpt-web应用做前端,使用rust 的candle做后端,本地运行小模型桌面应用

视频演示地址 https://www.bilibili.com/video/BV17j421X7Zc/ 【Tauri】&#xff08;2&#xff09;&#xff1a;使用Tauri应用开发&#xff0c;使用开源的Chatgpt-web应用做前端&#xff0c;使用rust 的candle做后端&#xff0c;本地运行小模型桌面应用 1&#xff0c;做一个免…

编写Makefile

现在我们将创建一个程序&#xff0c;该程序能够读取次位码文件并打印其中定义的函数名称&#xff0c;以及它们的基本块数&#xff0c;从而显示LLVM库的易用性 什么是Makefile&#xff1f; C语言中&#xff0c;我们使用visual studio开发软件时候&#xff0c;写程序开始时候都…

复旦TravelPlanner让大语言模型挑战旅程规划

引言&#xff1a;探索语言智能的新疆界——旅行规划 在人工智能的发展历程中&#xff0c;规划一直是核心追求之一。然而&#xff0c;由于缺乏人类水平规划所需的多种认知基础&#xff0c;早期的AI代理主要集中在受限的环境中。随着大语言模型&#xff08;LLMs&#xff09;的出…

vue3-应用规模化-路由和状态

客户端 vs. 服务端路由 服务端路由指的是服务器根据用户访问的 URL 路径返回不同的响应结果。当我们在一个传统的服务端渲染的 web 应用中点击一个链接时&#xff0c;浏览器会从服务端获得全新的 HTML&#xff0c;然后重新加载整个页面。 然而&#xff0c;在单页面应用中&…

python伯努利多项式

文章目录 伯努利数和多项式sympy实现 伯努利数是一种在数学、物理和工程中广泛应用的特殊数列&#xff0c;以瑞士数学家雅各布伯努利&#xff08;Jacob Bernoulli&#xff09;的名字命名&#xff0c;并在许多领域中发挥重要作用。在数学中&#xff0c;它们与斐波那契数列、卡塔…