- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我将异步请求包装在 Combine 发布者中,以便它们可以轻松地跨不同管道使用。
消费者可能会按以下方式保留这些发布者:
struct Dependencies {
var loadImageRequest: AnyPublisher<UIImage, Never>
var saveToDatabaseRequest: AnyPublisher<Void, Never>
var saveToUserDefaultsRequest: AnyPublisher<Never, Never>
}
两种更常见的请求类型是:
AnyPublisher<Never, Never>
似乎是表达这种类型的好方法。这可以通过 Empty<Never, Never>(completeImmediately: true)
轻松构建。 AnyPublisher<Void, Never>
对这些请求类型进行建模。构建这些的一种简单方法是通过 Future<Void, Never>() { promise in promise(.success(()))}
。 AnyPublisher<Never, Never>
和
AnyPublisher<Void, Never>
。
Never -> Void
,立即完成let neverPublisher: AnyPublisher<Never, Never> = ...
let voidPublisher: AnyPublisher<Void, Never> = neverPublisher
.map { _ in () }
.append(Just(()))
.eraseToAnyPublisher()
Void -> Never
, 等到 Void 完成let voidPublisher: AnyPublisher<Void, Never> = ...
let neverPublisher: AnyPublisher<Never, Never> = voidPublisher
.ignoreOutput()
.eraseToAnyPublisher()
Void -> Never
,立即完成handleEvents
,并且需要在某处定义 cancellables
:let cancellables: Set<AnyCancellable> = []
let voidPublisher: AnyPublisher<Void, Never> = ...
let neverPublisher: AnyPublisher<Never, Never> = Empty<Never, Never>(completeImmediately: true)
.handleEvents(receiveCompletion: { _ in voidPublisher.sink(receiveValue: { _ in }).store(in: &cancellables) })
.eraseToAnyPublisher()
Never -> Void
,立即完成)而无需同时调用 map
和 append
? (例如,类似于如何使用 ignoreOutput
来解决第二次转换?) Void -> Never
的第三次转换( cancellables
,立即完成)? 最佳答案
我还没有找到更优雅的方法来做#2。
这是一个更好的 #3 ( Void -> Never
,立即完成) 解决方案:
let voidPublisher: AnyPublisher<Void, Never> = ...
let neverPublisher: AnyPublisher<Never, Never> = Publishers.Merge(Just<Void>(()), saveToDatabase)
.first()
.ignoreOutput()
.eraseToAnyPublisher()
import Combine
import Foundation
let delaySec: TimeInterval = 0.1
let halfDelaySec: TimeInterval = delaySec / 2
let halfDelayMicroSeconds: useconds_t = useconds_t(halfDelaySec * 1_000_000)
let sleepBufferMicroSeconds: useconds_t = useconds_t(0.01 * 1_000_000)
var cancellables = [AnyCancellable]()
var output: [String] = []
func performVoidAction(voidPublisher: AnyPublisher<Void, Never>) {
voidPublisher
.handleEvents(
receiveCompletion: { _ in output.append("performVoidAction - completion") },
receiveCancel: { output.append("performVoidAction - cancel") })
.sink(receiveValue: { output.append("performVoidAction - sink") })
.store(in: &cancellables)
}
func performNeverAction(neverPublisher: AnyPublisher<Never, Never>) {
neverPublisher
.handleEvents(
receiveCompletion: { _ in output.append("performNeverAction - completion") },
receiveCancel: { output.append("performNeverAction - cancel") })
.sink(receiveValue: { _ in output.append("performNeverAction - sink") })
.store(in: &cancellables)
}
func makeSaveToDatabasePublisher() -> AnyPublisher<Void, Never> {
Deferred { _saveToDatabase() }.eraseToAnyPublisher()
}
func makeSaveToUserDefaultsPublisher() -> AnyPublisher<Never, Never> {
Deferred { _saveToUserDefaults() }.eraseToAnyPublisher()
}
// --->(Void)|
// AnyPublisher<Void, Never> wraps an API that does something and finishes upon completion.
private func _saveToDatabase() -> AnyPublisher<Void, Never> {
return Future<Void, Never> { promise in
output.append("saving to database")
DispatchQueue.global(qos: .userInitiated).asyncAfter(deadline: DispatchTime.now() + delaySec) {
output.append("saved to database")
promise(.success(()))
}
}.eraseToAnyPublisher()
}
// |
// AnyPublisher<Never, Never> wraps an API that does something and completes immediately, it does not wait for completion.
private func _saveToUserDefaults() -> AnyPublisher<Never, Never> {
output.append("saved to user defaults")
return Empty<Never, Never>(completeImmediately: true)
.eraseToAnyPublisher()
}
func assert(_ value: Bool) -> String {
value ? "✅" : "❌"
}
// tests
assert(output.isEmpty)
var saveToDatabase = makeSaveToDatabasePublisher()
assert(output.isEmpty, "It should not fire the action yet.")
// verify database save, first time
performVoidAction(voidPublisher: saveToDatabase)
assert(!output.isEmpty && output.removeFirst() == "saving to database")
assert(output.isEmpty)
usleep(halfDelayMicroSeconds + sleepBufferMicroSeconds)
assert(output.isEmpty)
usleep(halfDelayMicroSeconds + sleepBufferMicroSeconds)
assert(!output.isEmpty && output.removeFirst() == "saved to database")
assert(!output.isEmpty && output.removeFirst() == "performVoidAction - sink")
assert(!output.isEmpty && output.removeFirst() == "performVoidAction - completion")
assert(output.isEmpty)
// verify database save, second time
performVoidAction(voidPublisher: saveToDatabase)
assert(!output.isEmpty && output.removeFirst() == "saving to database")
assert(output.isEmpty)
usleep(halfDelayMicroSeconds + sleepBufferMicroSeconds)
assert(output.isEmpty)
usleep(halfDelayMicroSeconds + sleepBufferMicroSeconds)
assert(!output.isEmpty && output.removeFirst() == "saved to database")
assert(!output.isEmpty && output.removeFirst() == "performVoidAction - sink")
assert(!output.isEmpty && output.removeFirst() == "performVoidAction - completion")
assert(output.isEmpty)
var saveToUserDefaults = makeSaveToUserDefaultsPublisher()
assert(output.isEmpty, "It should not fire the action yet.")
// verify user defaults save, first time
performNeverAction(neverPublisher: saveToUserDefaults)
assert(!output.isEmpty && output.removeFirst() == "saved to user defaults")
assert(!output.isEmpty && output.removeFirst() == "performNeverAction - completion")
assert(output.isEmpty) // 'perform never action' should never be output
// verify user defaults save, second time
performNeverAction(neverPublisher: saveToUserDefaults)
assert(!output.isEmpty && output.removeFirst() == "saved to user defaults")
assert(!output.isEmpty && output.removeFirst() == "performNeverAction - completion")
assert(output.isEmpty) // 'perform never action' should never be output
// MARK: - Problem: AnyPublisher<Never, Never> -> AnyPublisher<Void, Never>
// MARK: Solution 1
// `|` ➡️ `(Void)|`
performVoidAction(
voidPublisher: saveToUserDefaults
.map { _ in () }
.append(Just(()))
.eraseToAnyPublisher())
assert(output.removeFirst() == "saved to user defaults")
assert(!output.isEmpty && output.removeFirst() == "performVoidAction - sink")
assert(!output.isEmpty && output.removeFirst() == "performVoidAction - completion")
assert(output.isEmpty) // 'perform never action' should never be output"
// MARK: - Problem: AnyPublisher<Void, Never> -> AnyPublisher<Never, Never>
// MARK: Solution 2 (Wait)
// `--->(Void)|` ➡️ `--->|`
performNeverAction(
neverPublisher: saveToDatabase.ignoreOutput().eraseToAnyPublisher())
assert(!output.isEmpty && output.removeFirst() == "saving to database")
assert(output.isEmpty)
usleep(halfDelayMicroSeconds + sleepBufferMicroSeconds)
assert(output.isEmpty)
usleep(halfDelayMicroSeconds + sleepBufferMicroSeconds)
assert(!output.isEmpty && output.removeFirst() == "saved to database")
assert(!output.isEmpty && output.removeFirst() == "performNeverAction - completion")
assert(output.isEmpty)
// MARK: Solution 3 (No wait)
// `--->(Void)|` ➡️ `|`
performNeverAction(
neverPublisher: Publishers.Merge(Just<Void>(()), saveToDatabase)
.first()
.ignoreOutput()
.eraseToAnyPublisher())
assert(!output.isEmpty && output.removeFirst() == "performNeverAction - completion")
assert(!output.isEmpty && output.removeFirst() == "saving to database")
assert(output.isEmpty)
usleep(halfDelayMicroSeconds + sleepBufferMicroSeconds)
assert(output.isEmpty)
usleep(halfDelayMicroSeconds + sleepBufferMicroSeconds)
assert(!output.isEmpty && output.removeFirst() == "saved to database")
assert(output.isEmpty)
print("done")
最后,以下是作为 Publisher 运算符(operator)的解决方案:
extension Publisher where Output == Never {
func asVoid() -> AnyPublisher<Void, Failure> {
self
.map { _ in () }
.append(Just(()).setFailureType(to: Failure.self))
.eraseToAnyPublisher()
}
}
extension Publisher where Output == Void {
func asNever(completeImmediately: Bool) -> AnyPublisher<Never, Failure> {
if completeImmediately {
return Just<Void>(())
.setFailureType(to: Failure.self)
.merge(with: self)
.first()
.ignoreOutput()
.eraseToAnyPublisher()
} else {
return self
.ignoreOutput()
.eraseToAnyPublisher()
}
}
}
关于swift - 如何转换为/从 AnyPublisher<Void, Never> 和 AnyPublisher<Never, Never>?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62856674/
我从 RESTful 服务器加载端点,其中一些端点是多页的。它们由 header 响应中的“x-pages”字段表示。我想创建一个发布者,它将所有页面中的所有对象作为单个数组返回。 最后一个 retu
如何将数组某个元素的发布者转换为所述元素的发布者(但有更多事件)? 例如我怎样才能转换 AnyPublisher至AnyPublisher ? 我想也许 RxSwift 用它的 from operat
我将异步请求包装在 Combine 发布者中,以便它们可以轻松地跨不同管道使用。 消费者可能会按以下方式保留这些发布者: struct Dependencies { var loadImageRe
func testData()->AnyPublisher { var data = DummyData().decodeClaimDetails()! return (Jus
我只是在学习如何使用Combine。我有使用 Rx(RxSwift 和 RxJava)的经验,我注意到它非常相似。 然而,完全不同的一件事(而且有点烦人)是 Publisher协议(protocol)
AnyPublisher 在 Combine 中的作用是什么,以及为什么在许多示例中,包括在 WWDC Combine In practice, 27:40 中他们返回 AnyPublisher,使用
如何转换 Just至AnyPublisher .当我使用 eraseToAnyPublisher()类型为 AnyPublisher这与 AnyPublisher 不同 例如,我有一个简单的函数,我想
我考虑一下有什么区别 @Published var isLoggedIn: Bool = false var isLoggedIn: AnyPublisher 我知道在第一种情况下,我可以直接在 Sw
链接 AnyPublisher 的典型方法是使用 Combine 运算符,例如 flatMap。 class MyService { func getUserList() -> AnyPubl
我是一名优秀的程序员,十分优秀!