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

相关文章

使用Python将PDF表格自动提取并写入Word文档表格

《使用Python将PDF表格自动提取并写入Word文档表格》在实际办公与数据处理场景中,PDF文件里的表格往往无法直接复制到Word中,本文将介绍如何使用Python从PDF文件中提取表格数据,并将... 目录引言1. 加载 PDF 文件并准备 Word 文档2. 提取 PDF 表格并创建 Word 表格

使用Python实现局域网远程监控电脑屏幕的方法

《使用Python实现局域网远程监控电脑屏幕的方法》文章介绍了两种使用Python在局域网内实现远程监控电脑屏幕的方法,方法一使用mss和socket,方法二使用PyAutoGUI和Flask,每种方... 目录方法一:使用mss和socket实现屏幕共享服务端(被监控端)客户端(监控端)方法二:使用PyA

Python使用Matplotlib和Seaborn绘制常用图表的技巧

《Python使用Matplotlib和Seaborn绘制常用图表的技巧》Python作为数据科学领域的明星语言,拥有强大且丰富的可视化库,其中最著名的莫过于Matplotlib和Seaborn,本篇... 目录1. 引言:数据可视化的力量2. 前置知识与环境准备2.1. 必备知识2.2. 安装所需库2.3

Python数据验证神器Pydantic库的使用和实践中的避坑指南

《Python数据验证神器Pydantic库的使用和实践中的避坑指南》Pydantic是一个用于数据验证和设置的库,可以显著简化API接口开发,文章通过一个实际案例,展示了Pydantic如何在生产环... 目录1️⃣ 崩溃时刻:当你的API接口又双叒崩了!2️⃣ 神兵天降:3行代码解决验证难题3️⃣ 深度

Linux内核定时器使用及说明

《Linux内核定时器使用及说明》文章详细介绍了Linux内核定时器的特性、核心数据结构、时间相关转换函数以及操作API,通过示例展示了如何编写和使用定时器,包括按键消抖的应用... 目录1.linux内核定时器特征2.Linux内核定时器核心数据结构3.Linux内核时间相关转换函数4.Linux内核定时

python中的flask_sqlalchemy的使用及示例详解

《python中的flask_sqlalchemy的使用及示例详解》文章主要介绍了在使用SQLAlchemy创建模型实例时,通过元类动态创建实例的方式,并说明了如何在实例化时执行__init__方法,... 目录@orm.reconstructorSQLAlchemy的回滚关联其他模型数据库基本操作将数据添

Spring配置扩展之JavaConfig的使用小结

《Spring配置扩展之JavaConfig的使用小结》JavaConfig是Spring框架中基于纯Java代码的配置方式,用于替代传统的XML配置,通过注解(如@Bean)定义Spring容器的组... 目录JavaConfig 的概念什么是JavaConfig?为什么使用 JavaConfig?Jav

Java使用Spire.Doc for Java实现Word自动化插入图片

《Java使用Spire.DocforJava实现Word自动化插入图片》在日常工作中,Word文档是不可或缺的工具,而图片作为信息传达的重要载体,其在文档中的插入与布局显得尤为关键,下面我们就来... 目录1. Spire.Doc for Java库介绍与安装2. 使用特定的环绕方式插入图片3. 在指定位

Springboot3 ResponseEntity 完全使用案例

《Springboot3ResponseEntity完全使用案例》ResponseEntity是SpringBoot中控制HTTP响应的核心工具——它能让你精准定义响应状态码、响应头、响应体,相比... 目录Spring Boot 3 ResponseEntity 完全使用教程前置准备1. 项目基础依赖(M

Java使用Spire.Barcode for Java实现条形码生成与识别

《Java使用Spire.BarcodeforJava实现条形码生成与识别》在现代商业和技术领域,条形码无处不在,本教程将引导您深入了解如何在您的Java项目中利用Spire.Barcodefor... 目录1. Spire.Barcode for Java 简介与环境配置2. 使用 Spire.Barco