Swift Combine 使用 print 操作符调试管道 从入门到精通二十四

本文主要是介绍Swift Combine 使用 print 操作符调试管道 从入门到精通二十四,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 的更新 从入门到精通十九
  20. Swift Combine 使用 ObservableObject 与 SwiftUI 模型作为发布源 从入门到精通二十
  21. Swift Combine 使用 XCTestExpectation 测试发布者 从入门到精通二十一
  22. Swift Combine 使用 PassthroughSubject 测试订阅者 从入门到精通二十二
  23. Swift Combine 使用从 PassthroughSubject 预定好的发送的事件测试订阅者 从入门到精通二十三
    在这里插入图片描述

1. 使用 print 操作符调试管道

目的:为了了解管道中正在发生的事情,查看所有控制事件和数据交互。

我获取的最详细的信息来自有选择地使用 print 操作符。 缺点是它打印了大量信息,因此输出可能很快变得非常庞大。 要理解简单的管道,使用 .print() 作为没有任何参数的操作符是非常简单的。 一旦你想要添加多个 print 操作符,你可能要使用 string 参数,该参数会作为前缀放在输出中。

示例 级联多个 UI 更新,包括网络请求 在几个地方都有用到它,使用比较长的描述性前缀,以明确是哪个管道在提供信息。

通过连接到一个私有的 @Published 的变量 —— githubUserData,两个管道被层叠到了一起。 该示例代码中的两个相关管道:

UIKit-Combine/GithubViewController.swift

usernameSubscriber = $username.throttle(for: 0.5, scheduler: myBackgroundQueue, latest: true)// ^^ scheduler myBackGroundQueue publishes resulting elements// into that queue, resulting on this processing moving off the// main runloop..removeDuplicates().print("username pipeline: ") // debugging output for pipeline.map { username -> AnyPublisher<[GithubAPIUser], Never> inreturn GithubAPI.retrieveGithubUser(username: username)}// ^^ type returned in the pipeline is a Publisher, so we use// switchToLatest to flatten the values out of that// pipeline to return down the chain, rather than returning a// publisher down the pipeline..switchToLatest()// using a sink to get the results from the API search lets us// get not only the user, but also any errors attempting to get it..receive(on: RunLoop.main).assign(to: \.githubUserData, on: self)// using .assign() on the other hand (which returns an
// AnyCancellable) *DOES* require a Failure type of <Never>
repositoryCountSubscriber = $githubUserData.print("github user data: ").map { userData -> String inif let firstUser = userData.first {return String(firstUser.public_repos)}return "unknown"}.receive(on: RunLoop.main).assign(to: \.text, on: repositoryCountLabel)

当你运行 UIKit-Combine 示例代码时,随着我慢慢的输入用户名 heckj,终端会显示以下输出。 在进行这些查找的过程中,在最终的帐户之前发现并检索到了另外两个 github 帐户(hec 和 heck)。

模拟器的交互输出

username pipeline: : receive subscription: (RemoveDuplicates)
username pipeline: : request unlimited
github user data: : receive subscription: (CurrentValueSubject)
github user data: : request unlimited
github user data: : receive value: ([])
username pipeline: : receive value: ()
github user data: : receive value: ([])Set username to  h
username pipeline: : receive value: (h)
github user data: : receive value: ([])Set username to  he
username pipeline: : receive value: (he)
github user data: : receive value: ([])Set username to  hec
username pipeline: : receive value: (hec)Set username to  heck
github user data: : receive value: ([UIKit_Combine.GithubAPIUser(login: "hec", public_repos: 3, avatar_url: "https://avatars3.githubusercontent.com/u/53656?v=4")])username pipeline: : receive value: (heck)
github user data: : receive value: ([UIKit_Combine.GithubAPIUser(login: "heck", public_repos: 6, avatar_url: "https://avatars3.githubusercontent.com/u/138508?v=4")])Set username to  heckj
username pipeline: : receive value: (heckj)
github user data: : receive value: ([UIKit_Combine.GithubAPIUser(login: "heckj", public_repos: 69, avatar_url: "https://avatars0.githubusercontent.com/u/43388?v=4")])

一些放在 sink 闭包中,用来查看最终结果的无关打印语句已被删除。

你可以在开始时看到初始化订阅的设置,然后看到通知,包括通过 print 操作符传递的值的调试信息。 虽然上面的示例内容中未显示它,但你还会在出现错误时看到取消管道的事件,或在发布者报告没有进一步数据时的 completions 事件。

在操作符两侧使用 print 来了解其具体的操作方式也很有用。

一个这样做的例子如下,利用前缀显示 retry 操作符及其工作原理:

UsingCombineTests/RetryPublisherTests.swift

func testRetryWithOneShotFailPublisher() {// setuplet _ = Fail(outputType: String.self, failure: TestFailureCondition.invalidServerResponse).print("(1)>")  // 1.retry(3).print("(2)>")  // 2.sink(receiveCompletion: { fini inprint(" ** .sink() received the completion:", String(describing: fini))}, receiveValue: { stringValue inXCTAssertNotNil(stringValue)print(" ** .sink() received \(stringValue)")})
}
  1. 前缀 (1) 是显示 retry 操作符上方的交互行为。
  2. 前缀 (2) 是显示 retry 操作符之后的交互行为。

单元测试的输出

Test Suite 'Selected tests' started at 2019-07-26 15:59:48.042
Test Suite 'UsingCombineTests.xctest' started at 2019-07-26 15:59:48.043
Test Suite 'RetryPublisherTests' started at 2019-07-26 15:59:48.043
Test Case '-[UsingCombineTests.RetryPublisherTests testRetryWithOneShotFailPublisher]' started.
(1)>: receive subscription: (Empty) 
(1)>: receive error: (invalidServerResponse)
(1)>: receive subscription: (Empty)
(1)>: receive error: (invalidServerResponse)
(1)>: receive subscription: (Empty)
(1)>: receive error: (invalidServerResponse)
(1)>: receive subscription: (Empty)
(1)>: receive error: (invalidServerResponse)
(2)>: receive error: (invalidServerResponse) ** .sink() received the completion: failure(UsingCombineTests.RetryPublisherTests.TestFailureCondition.invalidServerResponse)
(2)>: receive subscription: (Retry)
(2)>: request unlimited
(2)>: receive cancel
Test Case '-[UsingCombineTests.RetryPublisherTests testRetryWithOneShotFailPublisher]' passed (0.010 seconds).
Test Suite 'RetryPublisherTests' passed at 2019-07-26 15:59:48.054.Executed 1 test, with 0 failures (0 unexpected) in 0.010 (0.011) seconds
Test Suite 'UsingCombineTests.xctest' passed at 2019-07-26 15:59:48.054.Executed 1 test, with 0 failures (0 unexpected) in 0.010 (0.011) seconds
Test Suite 'Selected tests' passed at 2019-07-26 15:59:48.057.Executed 1 test, with 0 failures (0 unexpected) in 0.010 (0.015) seconds
  1. 在测试例子中,发布者总是返回失败,在输出结果中可以看到带有前缀 (1) 的错误信息,然后 retry 操作符触发重新订阅。
  2. 在其中4次尝试(3次"重试")之后,你就会看到从管道中输出的错误。 当错误到达 sink 后,你会看到发出的 cancel 信号,该信号在重试操作符之后停止。

虽然非常有效,但 print 操作符是一个钝器,它会生成大量的输出,你必须分析和审查它们以得到你想要的信息。 如果你想让标识和打印的内容更具选择性,或者如果你需要处理传输的数据才能更有意义地使用它们,那么你可以查看 handleEvents 操作符。 有关如何使用此操作符进行调试的更多详细信息,请查阅 使用 handleEvents 操作符调试管道。

参考

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

代码

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

这篇关于Swift Combine 使用 print 操作符调试管道 从入门到精通二十四的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

SpringBoot使用GZIP压缩反回数据问题

《SpringBoot使用GZIP压缩反回数据问题》:本文主要介绍SpringBoot使用GZIP压缩反回数据问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录SpringBoot使用GZIP压缩反回数据1、初识gzip2、gzip是什么,可以干什么?3、Spr

Spring Boot 集成 Quartz并使用Cron 表达式实现定时任务

《SpringBoot集成Quartz并使用Cron表达式实现定时任务》本篇文章介绍了如何在SpringBoot中集成Quartz进行定时任务调度,并通过Cron表达式控制任务... 目录前言1. 添加 Quartz 依赖2. 创建 Quartz 任务3. 配置 Quartz 任务调度4. 启动 Sprin

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

Java使用SLF4J记录不同级别日志的示例详解

《Java使用SLF4J记录不同级别日志的示例详解》SLF4J是一个简单的日志门面,它允许在运行时选择不同的日志实现,这篇文章主要为大家详细介绍了如何使用SLF4J记录不同级别日志,感兴趣的可以了解下... 目录一、SLF4J简介二、添加依赖三、配置Logback四、记录不同级别的日志五、总结一、SLF4J

使用Python实现一个优雅的异步定时器

《使用Python实现一个优雅的异步定时器》在Python中实现定时器功能是一个常见需求,尤其是在需要周期性执行任务的场景下,本文给大家介绍了基于asyncio和threading模块,可扩展的异步定... 目录需求背景代码1. 单例事件循环的实现2. 事件循环的运行与关闭3. 定时器核心逻辑4. 启动与停

如何使用Nginx配置将80端口重定向到443端口

《如何使用Nginx配置将80端口重定向到443端口》这篇文章主要为大家详细介绍了如何将Nginx配置为将HTTP(80端口)请求重定向到HTTPS(443端口),文中的示例代码讲解详细,有需要的小伙... 目录1. 创建或编辑Nginx配置文件2. 配置HTTP重定向到HTTPS3. 配置HTTPS服务器

Java使用ANTLR4对Lua脚本语法校验详解

《Java使用ANTLR4对Lua脚本语法校验详解》ANTLR是一个强大的解析器生成器,用于读取、处理、执行或翻译结构化文本或二进制文件,下面就跟随小编一起看看Java如何使用ANTLR4对Lua脚本... 目录什么是ANTLR?第一个例子ANTLR4 的工作流程Lua脚本语法校验准备一个Lua Gramm

Java Optional的使用技巧与最佳实践

《JavaOptional的使用技巧与最佳实践》在Java中,Optional是用于优雅处理null的容器类,其核心目标是显式提醒开发者处理空值场景,避免NullPointerExce... 目录一、Optional 的核心用途二、使用技巧与最佳实践三、常见误区与反模式四、替代方案与扩展五、总结在 Java

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

Qt中QUndoView控件的具体使用

《Qt中QUndoView控件的具体使用》QUndoView是Qt框架中用于可视化显示QUndoStack内容的控件,本文主要介绍了Qt中QUndoView控件的具体使用,具有一定的参考价值,感兴趣的... 目录引言一、QUndoView 的用途二、工作原理三、 如何与 QUnDOStack 配合使用四、自