如何合并两个请求但 return 通用发布者?详情如下

How to combine two requests but return generic publisher? Details below

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

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

我想在调用主请求之前检查并更新该函数内的令牌,但在这种情况下,我不能 return 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 [=11=]
                // 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, Error>, Publishers.Decode<Publishers.MapKeyPath<URLSession.DataTaskPublisher, Data>, SomeTokenObject, JSONDecoder>>') to return type 'AnyPublisher<T, Error>'
与 .map.

类似

我添加了另一个 returning 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, .flatMap, .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, Error>, AnyPublisher<Void, Error>>' to return type 'AnyPublisher<T, Error>'
对于地图:Cannot convert return expression of type 'Publishers.Map<AnyPublisher<Void, Error>, AnyPublisher<T, Error>>' to return type '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() 来擦除 returned 发布者。

请记住,像 .flatMap(或 .map 和其他人)这样的运算符 return 他们自己的发布者,就像您在错误 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 函数)