【问题标题】:Why don't we have tryFlatMap operator in Combine?为什么我们在 Combine 中没有 tryFlatMap 运算符?
【发布时间】:2021-07-16 05:14:55
【问题描述】:

我们应该改用什么?
我很惊讶以前没有人问过这个问题。

【问题讨论】:

  • 至于why,只有苹果才能回答。至于替代方案,我认为没有内置运算符可以将 1-1 映射到 tryFlatMap 之类的东西,因此您需要实现自己的 Operator
  • 这是个好问题。我假设它因为缺少代码示例而被否决?

标签: swift combine


【解决方案1】:

您并不严格需要tryFlatMap,因为flatMap 的转换返回一个发布者。您可以在转换闭包中使用do/catch,如果发现错误,则返回Fail 发布者。

import Combine

func someFunction(of i: Int) throws -> AnyPublisher<Int, Error> {
    return Just(i + 1)
        .setFailureType(to: Error.self)
        .eraseToAnyPublisher()
}

let upstream: AnyPublisher<Int, Error> = Just(100)
    .setFailureType(to: Error.self)
    .eraseToAnyPublisher()

upstream
    .flatMap({ i -> AnyPublisher<Int, Error> in
        do {
            return try someFunction(of: i).eraseToAnyPublisher()
        } catch {
            return Fail(error: error).eraseToAnyPublisher()
        }
    })

如果您愿意,可以编写自己的 tryFlatMap 运算符:

extension Publisher {
    func tryFlatMap<Pub: Publisher>(
        maxPublishers: Subscribers.Demand = .unlimited,
        _ transform: @escaping (Output) throws -> Pub
    ) -> Publishers.FlatMap<AnyPublisher<Pub.Output, Error>, Self> {
        return flatMap(maxPublishers: maxPublishers, { input -> AnyPublisher<Pub.Output, Error> in
            do {
                return try transform(input)
                    .mapError { $0 as Error }
                    .eraseToAnyPublisher()
            } catch {
                return Fail(outputType: Pub.Output.self, failure: error)
                    .eraseToAnyPublisher()
            }
        })
    }
}

然后像这样使用它:

upstream
    .tryFlatMap { try someFunction(of: $0) }

【讨论】:

  • 感谢您的回答。我想出了另一种解决方案。我将在下面发布它作为答案。简而言之:tryFlatMap = tryMap + flatMap
【解决方案2】:

另一种解决方案。
tryFlatMap = tryMap + flatMap。

例如。
整个故事开始于我只是想打开一个可选的。如果它为零,我希望它只是失败。

let upstream = Just(siteURL)
    .tryMap { url -> URL in
        guard let url = url else { throw Errors.invalidSiteURL }
        return url
    }
    .flatMap {
        URLSession.shared.dataTaskPublisher(for: $0).mapError { $0 as Error }
    }

[已编辑]这样也可以:

let container = Just(siteURL)
    .tryMap { url -> URLSession.DataTaskPublisher in
        guard let url = url else { throw Errors.invalidSiteURL }
        return URLSession.shared.dataTaskPublisher(for: url)
    }
    .map { $0.mapError { $0 as Error } }
    .switchToLatest()

错误类型有点烦人。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-24
    • 2011-09-14
    • 1970-01-01
    • 2018-09-14
    • 1970-01-01
    • 2014-05-20
    • 1970-01-01
    相关资源
    最近更新 更多