Swift Combine 使用 flatMap 和 catch错误处理 从入门到精通十三

2024-02-14 17:44

本文主要是介绍Swift Combine 使用 flatMap 和 catch错误处理 从入门到精通十三,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 有序的异步操作 从入门到精通十二
    在这里插入图片描述

1. 错误处理

上述示例都假设,如果发生错误情况,订阅者将处理这些情况。 但是,你并不总是能够控制订阅者的要求——如果你使用 SwiftUI,情况可能如此。 在这些情况下,你需要构建管道,以便输出类型与订阅者的类型匹配。 这意味着你在处理管道内的任何错误。

例如,如果你正在使用 SwiftUI,并且你希望使用 assign 在按钮上设置 isEnabled 属性,则订阅者将有几个要求:

  1. 订阅者应匹配 <Bool, Never> 的类型输出
  2. 应该在主线程调用订阅者

如果发布者抛出一个错误(例如 URLSession.dataTaskPublisher ),你需要构建一个管道来转换输出类型,还需要处理管道内的错误,以匹配错误类型 <Never>

如何处理管道内的错误取决于管道的定义方式。 如果管道设置为返回单个结果并终止, 一个很好的例子就是 使用 catch 处理一次性管道中的错误。 如果管道被设置为持续更新,则错误处理要复杂一点。 这种情况下的一个很好的例子是 使用 flatMap 和 catch 在不取消管道的情况下处理错误。

2.使用 assertNoFailure 验证未发生失败

目的:验证管道内未发生错误

在管道中测试常量时,断言 assertNoFailure 非常有用,可将失败类型转换为 <Never>。 如果断言被触发,该操作符将导致应用程序终止(或测试时导致调试器崩溃)。

这对于验证已经处理过错误的常量很有用。 比如你确信你处理了错误,对管道进行了 map 操作,该操作可以将 <Error> 的失败类型转换为 <Never> 传给所需的订阅者。

更有可能的是,你希望将错误处理掉,而不是终止应用程序。 期待后面的 使用 catch 处理一次性管道中的错误 和 使用 flatMap 和 catch 在不取消管道的情况下处理错误 模式吧,它们会告诉你如何提供逻辑来处理管道中的错误。

3. 使用 catch 处理一次性管道中的错误

目的:如果你需要在管道内处理失败,例如在使用 assign 操作符或其他要求失败类型为 <Never> 的操作符之前,你可以使用 catch 来提供适当的逻辑。

catch 处理错误的方式,是将上游发布者替换为另一个发布者,这是你在闭包中用返回值提供的。

请注意,这实际上终止了管道。 如果你使用的是一次性发布者(不创建多个事件),那这就没什么。

例如,URLSession.dataTaskPublisher 是一个一次性的发布者,你可以使用 catch 在发生错误时返回默认值,以确保你得到响应结果。 扩展我们以前的示例以提供默认的响应:

struct IPInfo: Codable {// matching the data structure returned from ip.jsontest.comvar ip: String
}
let myURL = URL(string: "http://ip.jsontest.com")
// NOTE(heckj): you'll need to enable insecure downloads in your Info.plist for this example
// since the URL scheme is 'http'let remoteDataPublisher = URLSession.shared.dataTaskPublisher(for: myURL!)// the dataTaskPublisher output combination is (data: Data, response: URLResponse).map({ (inputTuple) -> Data inreturn inputTuple.data}).decode(type: IPInfo.self, decoder: JSONDecoder()) .catch { err in return Publishers.Just(IPInfo(ip: "8.8.8.8"))}.eraseToAnyPublisher()
  1. 通常,catch 操作符将被放置在几个可能失败的操作符之后,以便在之前任何可能的操作失败时提供回退或默认值。
  2. 使用 catch 时,你可以得到错误类型,并可以检查它以选择如何提供响应。
  3. Just 发布者经常用于启动另一个一次性管道,或在发生失败时直接提供默认的响应。

此技术的一个可能问题是,如果你希望原始发布者生成多个响应值,但使用 catch 之后原始管道就已结束了。 如果你正在创建一条对 @Published 属性做出响应的管道,那么在任何失败值激活 catch 操作符之后,管道将不再做出进一步响应。 有关此工作原理的详细信息,请参阅 catch

如果你要继续响应错误并处理它们,请参阅 使用 flatMap 和 catch 在不取消管道的情况下处理错误。

4. 在发生暂时失败时重试

目的: 当 .failure 发生时,retry 操作符可以被包含在管道中以重试订阅。

当向 dataTaskPublisher 请求数据时,请求可能会失败。 在这种情况下,你将收到一个带有 error.failure 事件。 当失败时,retry 操作符将允许你对相同请求进行一定次数的重试。 当发布者不发送 .failure 事件时,retry 操作符会传递结果值。 retry 仅在发送 .failure 事件时才在 Combine 管道内做出响应。

retry 收到 .failure 结束事件时,它重试的方式是给它所链接的操作符或发布者重新创建订阅。

当尝试请求连接不稳定的网络资源时,通常需要 retry 操作符,或者再次请求时可能会成功的情况。 如果指定的重试次数全部失败,则将 .failure 结束事件传递给订阅者。

在下面的示例中,我们将 retrydelay 操作符相结合使用。 我们使用延迟操作符在下一个请求之前使其出现少量随机延迟。 这使得重试的尝试行为被分隔开,使重试不会快速连续的发生。

此示例还包括使用 tryMap 操作符以更全面地检查从 dataTaskPublisher 返回的任何 URL 响应。 服务器的任何响应都由 URLSession 封装,并作为有效的响应转发。 URLSession 不将 404 Not Foundhttp 响应视为错误响应,也不将任何 50x 错误代码视作错误。 使用 tryMap,我们可检查已发送的响应代码,并验证它是 200 的成功响应代码。 在此示例中,如果响应代码不是 200 ,则会抛出一个异常 —— 这反过来又会导致 tryMap 操作符传递 .failure 事件,而不是数据。 此示例将 tryMap 设置在 retry 操作符 之后,以便仅在网站未响应时重新尝试请求。

let remoteDataPublisher = urlSession.dataTaskPublisher(for: self.URL!).delay(for: DispatchQueue.SchedulerTimeType.Stride(integerLiteral: Int.random(in: 1..<5)), scheduler: backgroundQueue) .retry(3) .tryMap { data, response -> Data in guard let httpResponse = response as? HTTPURLResponse,httpResponse.statusCode == 200 else {throw TestFailureCondition.invalidServerResponse}return data}.decode(type: PostmanEchoTimeStampCheckResponse.self, decoder: JSONDecoder()).subscribe(on: backgroundQueue).eraseToAnyPublisher()
  1. delay 操作符将流经过管道的结果保持一小段时间,在这个例子中随机选择1至5秒。通过在管道中添加延迟,即使原始请求成功,重试也始终会发生。
  2. 重试被指定为尝试3次。 如果每次尝试都失败,这将导致总共 4 次尝试 - 原始请求和 3 次额外尝试。
  3. tryMap 被用于检查 dataTaskPublisher 返回的数据,如果服务器的响应数据有效,但不是 200 HTTP 响应码,则返回 .failure 完成事件。

使用 retry 操作符与 URLSession.dataTaskPublisher 时,请验证你请求的 URL 如果反复请求或重试,不会产生副作用。 理想情况下,此类请求应具有幂等性。 如果没有,retry 操作符可能会发出多个请求,并产生非常意想不到的副作用。

参考

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

代码

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

这篇关于Swift Combine 使用 flatMap 和 catch错误处理 从入门到精通十三的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/709172

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数

Makefile简明使用教程

文章目录 规则makefile文件的基本语法:加在命令前的特殊符号:.PHONY伪目标: Makefilev1 直观写法v2 加上中间过程v3 伪目标v4 变量 make 选项-f-n-C Make 是一种流行的构建工具,常用于将源代码转换成可执行文件或者其他形式的输出文件(如库文件、文档等)。Make 可以自动化地执行编译、链接等一系列操作。 规则 makefile文件

使用opencv优化图片(画面变清晰)

文章目录 需求影响照片清晰度的因素 实现降噪测试代码 锐化空间锐化Unsharp Masking频率域锐化对比测试 对比度增强常用算法对比测试 需求 对图像进行优化,使其看起来更清晰,同时保持尺寸不变,通常涉及到图像处理技术如锐化、降噪、对比度增强等 影响照片清晰度的因素 影响照片清晰度的因素有很多,主要可以从以下几个方面来分析 1. 拍摄设备 相机传感器:相机传

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

数论入门整理(updating)

一、gcd lcm 基础中的基础,一般用来处理计算第一步什么的,分数化简之类。 LL gcd(LL a, LL b) { return b ? gcd(b, a % b) : a; } <pre name="code" class="cpp">LL lcm(LL a, LL b){LL c = gcd(a, b);return a / c * b;} 例题:

git使用的说明总结

Git使用说明 下载安装(下载地址) macOS: Git - Downloading macOS Windows: Git - Downloading Windows Linux/Unix: Git (git-scm.com) 创建新仓库 本地创建新仓库:创建新文件夹,进入文件夹目录,执行指令 git init ,用以创建新的git 克隆仓库 执行指令用以创建一个本地仓库的