Swift 使用组合运算符将Future转换为Publisher
我使用的API(Firebase)为其大多数方法调用公开了异步接口。对于我通过自己的API发出的每个请求,如果存在这样的令牌,我希望添加一个用户令牌作为头。我试图使整个过程成为联合收割机中同一管道的一部分 我有以下代码:Swift 使用组合运算符将Future转换为Publisher,swift,generics,combine,Swift,Generics,Combine,我使用的API(Firebase)为其大多数方法调用公开了异步接口。对于我通过自己的API发出的每个请求,如果存在这样的令牌,我希望添加一个用户令牌作为头。我试图使整个过程成为联合收割机中同一管道的一部分 我有以下代码: struct Response<T> { let value: T let response: URLResponse } ... func makeRequest<T: Decodable>(_ req: URLRequest, _
struct Response<T> {
let value: T
let response: URLResponse
}
...
func makeRequest<T: Decodable>(_ req: URLRequest, _ decoder: JSONDecoder = JSONDecoder()) -> AnyPublisher<T, Error> {
var request = req
return Future<String?, Error> { promise in
if let currentUser = Auth.auth().currentUser {
currentUser.getIDToken() { (idToken, error) in
if error != nil {
promise(.failure(error!))
} else {
promise(.success(idToken))
}
}
} else {
promise(.success(nil))
}
}
.map { idToken -> URLSession.DataTaskPublisher in
if idToken != nil {
request.addValue("Bearer \(idToken!)", forHTTPHeaderField: "Authorization")
}
return URLSession.shared.dataTaskPublisher(for: request)
}
.tryMap { result -> Response<T> in
let value = try decoder.decode(T.self, from: result.data)
return Response(value: value, response: result.response)
}
.receive(on: DispatchQueue.main)
.map(\.value)
.eraseToAnyPublisher()
}
struct响应{
let值:T
let response:URLResponse
}
...
func makeRequest(req:URLRequest,decoder:JSONDecoder=JSONDecoder())->AnyPublisher{
var请求=req
回报未来{承诺未来}
如果让currentUser=Auth.Auth().currentUser{
中的currentUser.getIDToken(){(idToken,错误)
如果错误!=nil{
承诺(.failure(error!))
}否则{
承诺(.success(idToken))
}
}
}否则{
承诺(.success(无))
}
}
.map{idToken->URLSession.DataTaskPublisher位于
如果idToken!=nil{
request.addValue(“Bearer\(idToken!)”,forHTTPHeaderField:“Authorization”)
}
返回URLSession.shared.dataTaskPublisher(用于:请求)
}
.tryMap{result->中的响应
let value=try decoder.decode(T.self,from:result.data)
返回响应(值:value,响应:result.Response)
}
.receive(在:DispatchQueue.main上)
.map(\.value)
.删除任何发布者()
}
尝试对响应数据进行JSON解码时,tryMap运算符中出现错误:
“URLSession.DataTaskPublisher”类型的值没有成员“data”
我还在为联合收割机绞尽脑汁,但不明白我在这里做错了什么。任何帮助都将不胜感激 您正在尝试映射到另一个发布者。大多数情况下,这表明您需要
flatMap
。如果您改用map
,您将得到一个发布另一个发布者的发布者,这几乎肯定不是您想要的
但是,flatMap
要求上游发布服务器(promise)与您要映射到的发布服务器具有相同的故障类型。但是,在这种情况下,它们并不相同,因此您需要在数据会话发布服务器上调用maperro
,以更改其错误类型:
return Future<String?, Error> { promise in
promise(.failure(NSError()))
}
// flatMap and notice the change in return type
.flatMap { idToken -> Publishers.MapError<URLSession.DataTaskPublisher, Error> in
if idToken != nil {
request.addValue("Bearer \(idToken!)", forHTTPHeaderField: "Authorization")
}
return URLSession.shared.dataTaskPublisher(for: request)
// change the error type
.mapError { $0 as Error } // "as Error" isn't technically needed. Just for clarity
}
.tryMap { result -> Response<T> in
let value = try decoder.decode(T.self, from: result.data)
return Response(value: value, response: result.response)
}
.receive(on: DispatchQueue.main)
.map(\.value)
.eraseToAnyPublisher()
返回未来{promise in
承诺(.failure(NSError()))
}
//flatMap并注意返回类型的更改
.flatMap{idToken->publisher.maperor在中
如果idToken!=nil{
request.addValue(“Bearer\(idToken!)”,forHTTPHeaderField:“Authorization”)
}
返回URLSession.shared.dataTaskPublisher(用于:请求)
//更改错误类型
.mapError{$0 as Error}//“as Error”在技术上是不需要的。只是为了清楚起见
}
.tryMap{result->中的响应
let value=try decoder.decode(T.self,from:result.data)
返回响应(值:value,响应:result.Response)
}
.receive(在:DispatchQueue.main上)
.map(\.value)
.删除任何发布者()
您正试图映射到另一个发布者。大多数情况下,这表明您需要flatMap
。如果您改用map
,您将得到一个发布另一个发布者的发布者,这几乎肯定不是您想要的
但是,flatMap
要求上游发布服务器(promise)与您要映射到的发布服务器具有相同的故障类型。但是,在这种情况下,它们并不相同,因此您需要在数据会话发布服务器上调用maperro
,以更改其错误类型:
return Future<String?, Error> { promise in
promise(.failure(NSError()))
}
// flatMap and notice the change in return type
.flatMap { idToken -> Publishers.MapError<URLSession.DataTaskPublisher, Error> in
if idToken != nil {
request.addValue("Bearer \(idToken!)", forHTTPHeaderField: "Authorization")
}
return URLSession.shared.dataTaskPublisher(for: request)
// change the error type
.mapError { $0 as Error } // "as Error" isn't technically needed. Just for clarity
}
.tryMap { result -> Response<T> in
let value = try decoder.decode(T.self, from: result.data)
return Response(value: value, response: result.response)
}
.receive(on: DispatchQueue.main)
.map(\.value)
.eraseToAnyPublisher()
返回未来{promise in
承诺(.failure(NSError()))
}
//flatMap并注意返回类型的更改
.flatMap{idToken->publisher.maperor在中
如果idToken!=nil{
request.addValue(“Bearer\(idToken!)”,forHTTPHeaderField:“Authorization”)
}
返回URLSession.shared.dataTaskPublisher(用于:请求)
//更改错误类型
.mapError{$0 as Error}//“as Error”在技术上是不需要的。只是为了清楚起见
}
.tryMap{result->中的响应
let value=try decoder.decode(T.self,from:result.data)
返回响应(值:value,响应:result.Response)
}
.receive(在:DispatchQueue.main上)
.map(\.value)
.删除任何发布者()