本文首发于 Ficow Shen's Blog,原文地址: Combine 框架,从0到1 —— 5.Combine 中的 Subjects

内容概览

  • 前言
  • PassthroughSubject
  • CurrentValueSubject
  • Subject 作为订阅者
  • 常见用法
  • 总结

前言

正所谓,工欲善其事,必先利其器。在开始使用 Combine 进行响应式编程之前,建议您先了解 Combine 为您提供的各种发布者(Publishers)、操作符(Operators)、订阅者(Subscribers)。

Subject 是一类比较特殊的发布者,因为它同时也是订阅者。Combine 提供了两类 SubjectPassthroughSubjectCurrentValueSubject

如果您想了解更多 Publishers 的用法和注意事项,可以阅读:Combine 框架,从0到1 —— 5.Combine 提供的发布者(Publishers)

PassthroughSubject

官网文档

PassthroughSubject 可以向下游订阅者广播发送元素。使用 PassthroughSubject 可以很好地适应命令式编程场景。

如果没有订阅者,或者需求为0,PassthroughSubject 就会丢弃元素。

示例代码:

final class SubjectsDemo {

    private var cancellable: AnyCancellable?
private let passThroughtSubject = PassthroughSubject<Int, Never>() func passThroughtSubjectDemo() {
cancellable = passThroughtSubject
.sink {
print(#function, $0)
}
passThroughtSubject.send(1)
passThroughtSubject.send(2)
passThroughtSubject.send(3)
}
}

输出内容:

passThroughtSubjectDemo() 1

passThroughtSubjectDemo() 2

passThroughtSubjectDemo() 3

CurrentValueSubject

官网文档

CurrentValueSubject 包装一个值,当这个值发生改变时,它会发布一个新的元素给下游订阅者。

CurrentValueSubject 需要在初始化时提供一个默认值,您可以通过 value 属性访问这个值。在调用 send(_:) 方法发送元素后,这个缓存值也会被更新。

示例代码:

final class SubjectsDemo {

    private var cancellable: AnyCancellable?
private let currentValueSubject = CurrentValueSubject<Int, Never>(1) func currentValueSubjectDemo() {
cancellable = currentValueSubject
.sink { [unowned self] in
print(#function, $0)
print("Value of currentValueSubject:", self.currentValueSubject.value)
}
currentValueSubject.send(2)
currentValueSubject.send(3)
}
}

输出内容:

currentValueSubjectDemo() 1

Value of currentValueSubject: 1

currentValueSubjectDemo() 2

Value of currentValueSubject: 2

currentValueSubjectDemo() 3

Value of currentValueSubject: 3

Subject 作为订阅者

示例代码:

final class SubjectsDemo {

    private var cancellable1: AnyCancellable?
private var cancellable2: AnyCancellable? private let optionalCurrentValueSubject = CurrentValueSubject<Int?, Never>(nil) private func subjectSubscriber() {
cancellable1 = optionalCurrentValueSubject
.sink {
print(#function, $0)
}
cancellable2 = [1, 2, 3].publisher
.subscribe(optionalCurrentValueSubject)
}
}

optionalCurrentValueSubject 可以作为一个订阅者去订阅序列发布者 [1, 2, 3].publisher 发送的元素。

输出内容:

subjectSubscriber() nil

subjectSubscriber() Optional(1)

subjectSubscriber() Optional(2)

subjectSubscriber() Optional(3)

常见用法

在使用 Subject 时,我们往往不会将其暴露给调用方。这时候,可以使用 eraseToAnyPublisher 操作符来隐藏内部的 Subject

示例代码:

    struct Model {
let id: UUID
let name: String
} final class ViewModel {
private let modelSubject = CurrentValueSubject<Model?, Never>(nil)
var modelPublisher: AnyPublisher<Model?, Never> {
return modelSubject.eraseToAnyPublisher()
} func updateName(_ name: String) {
modelSubject.send(.init(id: UUID(), name: name))
}
}

外部调用者无法直接操控 ViewModel 内部的 Subject,这样可以让 ViewModel 更好地面对将来可能的改动。

外部调用者只需要知道 modelPublisherAnyPublisher<Model?, Never> 类型的发布者即可,无论内部采用了 CurrentValueSubject 还是 PassthroughSubject 甚至是其他的发布者。

总结

相比于其他的发布者来说, Subject 是比较容易理解的,而且也是最常用到的。

只可惜,对比 Rx 提供的 Subject,Combine 中的 Subject 无法设置缓冲的大小。也许某天苹果会对此做出调整吧~

最新文章

  1. Spring Boot异常处理详解
  2. Device Tree Usage( DTS文件语法)
  3. QQ面向对象设计
  4. android动态增加控件时控制样式的方法
  5. iOS开发——消息推送跳转
  6. Java线程之Phaser
  7. Python修改文件名
  8. c++实现将表达式转换为逆波兰表达式
  9. Kafka 源码剖析
  10. 浅析ConcurrentHashMap
  11. [置顶] android ListView包含Checkbox滑动时状态改变
  12. 【转】解决未能加载文件或程序集&#39;WebGrease‘的问题
  13. SlidingMenu的使用详解
  14. 环境与工具1:微信群刷屏 | itchat
  15. 升级本地部署的CRM到Dynamics 365及部分新特性介绍。
  16. SQLAlchemy中解决数据库访问时出现的Incorrect string value: xxx at row 484
  17. DMA 内存存取原理
  18. vs2017 打开附带的localdb v13
  19. iOS开发之--复制粘贴功能
  20. 微信sdk 图片上传 两种方法 上传一张显示一张 并附带微信图片放大功能和删除功能

热门文章

  1. [源码解析] Flink的Slot究竟是什么?(1)
  2. SPFA算法详解
  3. 前端Web APIS
  4. python123期末四题编程题 -无空隙回声输出-文件关键行数-字典翻转输出-《沉默的羔羊》之最多单词
  5. LeetCode 95 | 构造出所有二叉搜索树
  6. sourse insight总是代码一写长了,就自动换行
  7. printf size_t warning
  8. Unity CommandLine
  9. ctf古典密码从0到
  10. Activiti7 学习总结