如何组合两个请求但返回通用发布者?详情如下

问题描述

我有一个通用函数用于向服务器发送请求。 现在,在我发送请求之前,我需要检查会话令牌是否已过期并在需要时进行更新。

我的函数是这样的
func upload<T: Decodable>(some parameters here) -> AnyPublisher<T,Error>

我想在调用主请求之前检查并更新该函数中的令牌,但在这种情况下,我无法返回 AnyPublisher<T,Error>

func upload<T: Decodable>(some parameters here) -> AnyPublisher<T,Error> {
    if shouldUpdatetoken {
        let request = // prepare request
        let session = // prepare session
        return session.dataTaskPublisher(for: request)
            .map(\.data)
            .decode(type: SometokenObject.self,decoder: JSONDecoder())
            // here I wanted to save token and continue with 
            // the prevIoUs request 
            // but using .map,.flatMap,.compactMap will not return needed publisher
            // the error message I'll post below
            .map {
                // update token with $0
                // and continue with the main request
            }
    } else {
        return upload() // this will return AnyPublisher<T,Error> so it's ok here
    }
}

我在使用 .flatMap 时遇到的这个错误 Cannot convert return expression of type 'Publishers.FlatMap<AnyPublisher<T,Error>,Publishers.Decode<Publishers.MapKeyPath<URLSession.DataTaskPublisher,JSONDecoder.Input>,SometokenObject,JSONDecoder>>' (aka 'Publishers.FlatMap<AnyPublisher<T,Data>,JSONDecoder>>') to return type 'AnyPublisher<T,Error>'
.map 也类似。

添加了另一个返回 AnyPublisher函数,并想像那样在 shouldUpdatetoken 内部使用

func upload<T: Decodable>(some parameters here) -> AnyPublisher<T,Error> {
    if shouldUpdatetoken {
        return refreshToken() // returns AnyPublisher<Void,Error>
            // Now I need to continue with original request
            // and I'd like to use something like
            .flatMap { result -> AnyPublisher<T,Error>
                upload()
            }
            // but using .map,.compactMap will not return needed publisher
            // the error message I'll post below
            
    } else {
        return upload() // this will return AnyPublisher<T,Error> so it's ok here
    }
}

对于平面地图: Cannot convert return expression of type 'Publishers.FlatMap<AnyPublisher<T,AnyPublisher<Void,Error>>' to return type 'AnyPublisher<T,Error>'
对于地图:Cannot convert return expression of type 'Publishers.Map<AnyPublisher<Void,AnyPublisher<T,Error>'

也许我需要改用另一种方法? 我在应用程序周围有很多请求,所以在一个地方更新令牌是个好主意,但怎么做?

这是refreshToken()函数

func refreshToken() -> AnyPublisher<Void,Error> {
        let request = ...
        let session = ...
        return session.dataTaskPublisher(for: request)
            .map(\.data)
            .decode(type: SometokenObject.self,decoder: JSONDecoder())
            .map {
                // saved new token
            }
            .erasetoAnyPublisher()
    }

解决方法

你快到了。您需要 eraseToAnyPublisher() 对返回的发布者进行类型擦除。

请记住,像 .flatMap(或 .map 和其他人)这样的运算符返回他们自己的发布者,就像您在错误 Publishers.FlatMap<AnyPublisher<T,Error>,AnyPublisher<Void,Error>> 中看到的类型 - 您需要键入擦除:

func upload<T: Decodable>(some parameters here) -> AnyPublisher<T,Error> {
    if shouldUpdateToken {
        return refreshToken() // returns AnyPublisher<Void,Error>
            .flatMap { _ -> AnyPublisher<T,Error> in
                upload()
            }
            .eraseToAnyPublisher() // <- type-erase here
            
    } else {
        return upload() // actually "return"
    }
}

(并确保您不会在没有任何停止条件的情况下不断地递归调用相同的 upload 函数)