swift - Swift Combine 替代 Rx Observable.create
问题描述
我有一些使用 RxSwift 构建的代码,我正在尝试将其转换为使用 Apple 的 Combine 框架。
一种非常常见的模式是使用Observable.create
一次性可观察对象(通常是网络请求)。像这样的东西:
func loadWidgets() -> Observable<[Widget]> {
return Observable.create { observer in
// start the request when someone subscribes
let loadTask = WidgetLoader.request("allWidgets", completion: { widgets in
// publish result on success
observer.onNext(widgets)
observer.onComplete()
}, error: { error in
// publish error on failure
observer.onError()
})
// allow cancellation
return Disposable {
loadTask.cancel()
}
}
}
我正在尝试将其映射到Combine,但我无法弄清楚。我能得到的最接近的是使用 Future 来做这样的事情:
func loadWidgets() -> AnyPublisher<[Widget], Error> {
return Future<[Widget], Error> { resolve in
// start the request when someone subscribes
let loadTask = WidgetLoader.request("allWidgets", completion: { widgets in
// publish result on success
resolve(.success(widgets))
}, error: { error in
// publish error on failure
resolve(.failure(error))
})
// allow cancellation ???
}
}
如您所见,它完成了大部分工作,但无法取消。其次,未来不允许多个结果。
有没有办法做类似 RxObservable.create
模式的事情,它允许取消和可选的多个结果?
解决方案
我想我找到了一种模仿Observable.create
使用PassthroughSubject
in的方法Combine
。这是我制作的助手:
struct AnyObserver<Output, Failure: Error> {
let onNext: ((Output) -> Void)
let onError: ((Failure) -> Void)
let onComplete: (() -> Void)
}
struct Disposable {
let dispose: () -> Void
}
extension AnyPublisher {
static func create(subscribe: @escaping (AnyObserver<Output, Failure>) -> Disposable) -> Self {
let subject = PassthroughSubject<Output, Failure>()
var disposable: Disposable?
return subject
.handleEvents(receiveSubscription: { subscription in
disposable = subscribe(AnyObserver(
onNext: { output in subject.send(output) },
onError: { failure in subject.send(completion: .failure(failure)) },
onComplete: { subject.send(completion: .finished) }
))
}, receiveCancel: { disposable?.dispose() })
.eraseToAnyPublisher()
}
}
这是它在使用中的样子:
func loadWidgets() -> AnyPublisher<[Widget], Error> {
AnyPublisher.create { observer in
let loadTask = WidgetLoader.request("allWidgets", completion: { widgets in
observer.onNext(widgets)
observer.onComplete()
}, error: { error in
observer.onError(error)
})
return Disposable {
loadTask.cancel()
}
}
}
推荐阅读
- r - 数据框中的新列名称错误
- postgresql - 如何监控 PostgreSQL IOPS
- python - 处理完成时 Django 对客户端的响应
- php - 在 foreach 循环中重复 select2 项
- c++ - 如何强制此模板仅接受匹配类型的整数?
- nginx - 如何将所有请求的 HTTP 标头附加到路由器中
- pandas - 如何计算至少有 1 个非 NaN 值的月份?
- c# - 在 ASP.NET Core 中提交表单后如何保持 SelectListItem 值被选中?
- javascript - PrimeNG p-overlaypanel 不支持静态以外的位置
- windows - 如何使用 bat 文件更改 firefox print.always_print_silent 首选项?