![](/img/trans.png)
[英]Is there a way to share RxSwift's observable operator like just, from, of, etc?
[英]Creating a Combine's publisher like RxSwift's Observable.Create for an Alamofire request
我使用以下代码生成冷RxSwift Observable
:
func doRequest<T :Mappable>(request:URLRequestConvertible) -> Observable<T> {
let observable = Observable<T>.create { [weak self] observer in
guard let self = self else { return Disposables.create() }
self.session.request(request).validate().responseObject { (response: AFDataResponse<T>) in
switch response.result {
case .success(let obj):
observer.onNext(obj)
observer.onCompleted()
case .failure(let error):
let theError = error as Error
observer.onError(theError)
}
}
return Disposables.create()
}
return observable
}
其中Mappable
是基于ObjectMapper的类型,而self.session
是 Alamofire 的Session
对象。
我在 Apple 的Combine
框架中找不到与Observable.create {...}
等效的东西。 我只发现URLSession.shared.dataTaskPublisher(for:)
它使用 Apple 的URLSession
类创建发布者。
如何将上述 observable 转换为 Alamofire Combine 的发布者?
编辑:使用 rob 提供的解决方案,我得到了以下结果:
private let apiQueue = DispatchQueue(label: "API", qos: .default, attributes: .concurrent)
func doRequest<T>(request: URLRequestConvertible) -> AnyPublisher<T, AFError> where T : Mappable {
Deferred { [weak self] () -> Future<T, AFError> in
guard let self = self else {
return Future<T, AFError> { promise in
promise(.failure(.explicitlyCancelled)) }
}
return Future { promise in
self.session
.request(request)
.validate()
.responseObject { (response: AFDataResponse<T>) in
promise(response.result)
}
}
}
.handleEvents(receiveCompletion: { completion in
if case .failure (let error) = completion {
//handle the error
}
})
.receive(on: self.apiQueue)
.eraseToAnyPublisher()
}
EDIT2:我必须删除私有队列,因为它不需要,Alamofire 自己解析解码,因此删除队列及其用法( .receive(on: self.apiQueue)
)
您可以使用Future
将responseObject
的回调连接到 Combine Publisher
。 我没有方便的 Alamofire 进行测试,但我认为以下应该有效:
func doRequest<T: Mappable>(request: URLRequestConvertible) -> AnyPublisher<T, AFError> {
return Future { promise in
self.session
.request(request)
.validate()
.responseObject { (response: AFDataResponse<T>) in
promise(response.result)
}
}.eraseToAnyPublisher()
}
请注意,这比 RxSwift 版本要简单一些,因为promise
直接接受Result
,因此我们不必切换response.result
。
Future
是一种“不冷不热”的出版商。 它就像一个 hot observable 因为它立即执行它的 body 并且只执行一次,所以它立即启动 Alamofire 请求。 它也像一个冷的 observable,因为每个订阅者最终都会收到一个值或一个错误(假设你最终调用了promise
)。 Future
只执行一次它的主体,但它会缓存你传递给promise
的Result
。
您可以通过将Future
包装在Deferred
来创建一个真正冷的发布者:
func doRequest<T: Mappable>(request: URLRequestConvertible) -> AnyPublisher<T, AFError> {
return Deferred {
Future { promise in
self.session
.request(request)
.validate()
.responseObject { (response: AFDataResponse<T>) in
promise(response.result) }
}
}.eraseToAnyPublisher()
}
每次订阅时, Deferred
调用它的主体来创建一个新的内部Publisher
者。 因此,每次订阅时,您都会创建一个新的Future
,它将立即启动一个新的 Alamofire 请求。 如果您想使用retry
运算符,这很有用,如本问题所示。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.