Combine #13:资源管理
Source: Dev.to
请提供您希望翻译的正文内容,我将为您翻译成简体中文。
Source: …
share()
大多数 Combine 的 Publishers 都是 struct,它们仅描述一个 pipeline,并不保存共享状态。不会创建一个活跃的实例来持有数据,而是生成一个值,描述在有人订阅时如何产生流。因此,每一次订阅都会启动一个新的发布序列(即启动它自己的工作)。
share() 返回一个 Publisher.Share,它是基于 multicast(_:) 和 PassthroughSubject 实现的,会创建 唯一一次 对原始 Publisher 的订阅,并在多个订阅者之间共享。由于 Combine 在内部使用类来保存对订阅者的引用,这就产生了共享状态。
let shared = URLSession.shared
.dataTaskPublisher(for: URL(string: "https://ejemplo.com")!)
.map(\.data)
.share()
let subscription1 = shared.sink { /* … */ }
let subscription2 = shared.sink { /* … */ }
// 只会发起一次网络请求,结果会在两个订阅之间共享
当 share() 收到第一个订阅时,会启动输入 Publisher 的工作。这可能导致流在其他订阅到来之前就已经结束(发送完成事件),此时后续的订阅只能收到完成事件。
let shared = URLSession.shared
.dataTaskPublisher(for: URL(string: "https://ejemplo.com")!)
.map(\.data)
.share()
let subscription1 = shared.sink { /* … */ }
var subscription2: AnyCancellable? = nil
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
subscription2 = shared.sink { /* … */ } // 只会收到完成事件
}
multicast(_:)
multicast(_:) 使用 Subject 向多个订阅者发出值,并返回一个 ConnectablePublisher,这意味着它只有在收到 connect() 信号时才会订阅输入的 Publisher。
// Subject para emitir eventos del multicast.
// Recibe del flujo de entrada
let subject = PassthroughSubject<Data, URLError>()
// Se crea el Publisher multicast, envolviendo el subject
let multicasted = URLSession.shared
.dataTaskPublisher(for: URL(string: "https://ejemplo.com")!)
.map(\.data)
.multicast(subject: subject)
let subscription1 = multicasted.sink { /* … */ }
var subscription2: AnyCancellable? = nil
// Crear una segunda suscripción al multicast
DispatchQueue.main.asyncAfter(deadline: .now() + 5) {
subscription2 = multicasted.sink { /* … */ }
}
// Suscribir el multicast al dataTaskPublisher
DispatchQueue.main.asyncAfter(deadline: .now() + 6) {
let cancellable = multicasted.connect()
}
由于 multicast(_:) 返回 ConnectablePublisher,也可以使用 autoconnect() 让它在收到第一个订阅时立即订阅输入的 Publisher。
在只需要执行一次工作并发出一个值的场景下,可以使用 CurrentValueSubject。
Future
Future 是一个 Publisher(实现为 class,而不是 struct),它接受一个带有 Future.Promise 的闭包。该闭包只产生 一个值 然后结束。在闭包内部执行工作,完成后调用 promise 并传入结果或错误。
- 在创建
Future实例时,闭包会立即执行,不需要等待任何订阅者。 Future会保存 promise 的结果,并向 所有 订阅者(包括当前和未来的)发送该结果。
let future = Future { fulfill in
do {
let result = try performSomeWork()
fulfill(.success(result))
} catch {
fulfill(.failure(error))
}
}
let subscription1 = future.sink(
receiveCompletion: { _ in },
receiveValue: { value in print("1️⃣", value) }
)
let subscription2 = future.sink(
receiveCompletion: { _ in },
receiveValue: { value in print("2️⃣", value) }
)
复习问题
Combine 的 Publisher,是否每个订阅都会重复流的工作?
- 因为 Publisher 是保持内部状态的类。
- 因为 Combine 为每个订阅创建了一个新线程。
- 因为 Publisher 是结构体(
struct),仅描述管道且不共享状态。 - 因为订阅者必须手动使用
connect()进行连接。
Publisher 中的 share()
- 为每个订阅者创建独立的流副本。
- 取消重复的订阅。
- 对原始 Publisher 创建单一订阅,并在多个订阅者之间共享其结果。
- 将 Publisher 转换为
Subject。
使用 share() 的共享 Publisher 在流已经结束后进行
- 接收之前存储的值。
- 不接收任何值,只接收完成事件。
- 重新执行整个原始流。
- 导致运行时错误。
share() 用于哪里?
- 在
Future和Just中。 - 在
multicast(_:)和PassthroughSubject中。 - 在
CurrentValueSubject中。 - 在
DispatchQueue中。
multicast(_:) 与 share() 的比较
-
multicast(_:)不需要Subject。 -
multicast(_:)返回一个 ConnectablePublisher,需要通过connect()调用来连接。 -
multicast(_:)为每个订阅者重复工作。 -
share()允许多次手动连接,而multicast(_:)不允许。
使用 multicast(_:) 创建的 ConnectablePublisher 上的 autoconnect()
- 允许 Publisher 在收到第一个订阅时自动连接。
- 允许自动取消订阅。
- 将 Publisher 转换为
Future。 - 为后续订阅者保存结果。
share() 或 multicast(_:) 等其他 Publisher 的 Future
- 它是一个无状态的
structPublisher。 - 只发出错误,从不发出值。
- 仅在收到订阅后才执行。
- 它是一个类,在创建时立即执行工作并将结果保存给所有订阅者。
快速概览
- Publishers 在 Combine 中大多是
struct→ 每次订阅都会重新执行 pipeline。 share()创建对上游的唯一订阅并共享它。multicast(_:)需要一个Subject,并且由于是 connectable,需要调用connect()(或autoconnect())。Future是一个类,会立即执行其工作并将结果保存,以供后续任何订阅者使用。
关于 share()、multicast(_:) 和 autoconnect() 的问答
| 问题 | 回答 |
|---|---|
share() 在 Publisher 中的作用是什么? | ✅ 为原始 Publisher 创建唯一的订阅,并在多个订阅者之间共享其结果。 |
使用 share() 的共享 Publisher 是否在流已经结束后才进行? | ✅ 不会接收任何值,只会收到结束事件。 |
share() | ✅ 用于 multicast(_:) 和 PassthroughSubject。 |
multicast(_:) 与 share() 有何区别? | ✅ multicast(_:) 返回一个 ConnectablePublisher,需要调用 connect() 来启动。 |
在使用 multicast(_:) 创建的 ConnectablePublisher 上,autoconnect() 的作用是什么? | ✅ 使 Publisher 在收到第一个订阅时自动连接。 |
share() 或 multicast(_:) 等 Publisher 的 Future 是什么? | ✅ 是一种在创建时立即执行任务并将结果保存给所有订阅者的类。 |
快速概览(重复)
share()→ 单一内部订阅者,在内部共享值,仅向外部订阅者发送结束事件。multicast(_:)→ 返回一个 ConnectablePublisher;需要connect()(或autoconnect())来启动传输。autoconnect()→ 在收到 第一个订阅 时自动连接。Future→ 立即执行任务,并 保存 结果供后续任何订阅者使用。