结合:如何取消 flatMap 的发布者

Sea*_*ser 1 reactive-programming ios swift combine

此处是结合和反应式编程的新手,因此非常感谢您的帮助。

我有以下场景:我想构建一个用户界面,用户可以通过页面上的各种“过滤器”按钮过滤内容。当用户点击其中一个按钮时,我需要发出 API 请求以获取数据。

现在,我有一个发布者为我提供这些选择的“状态”,我将代码结构如下:

        state
            .publisher /* sends whenever 'state' updates behind the scenes */
            .debounce(for: 1.0, scheduler: DispatchQueue.main)
            .map { /*  create some URL request */ }
            .flatMap {
                URLSession.shared.dataTaskPublisher(for: someRequest)
                    .map { $0.data }
                    .decode(type: MyResponseType.self, decoder: JSONDecoder())
        }.sink(receiveCompletion: { (completion) in
            /// cancelled
        }) { (output) in
             /// go show my results
             /// Ideally, this is only called when the most recent API call finishes!
        }.store(in: &cancellables)
Run Code Online (Sandbox Code Playgroud)

但是,此实现在以下场景中存在错误:如果一个事件通过 flatMap 来触发请求,并且后续事件在网络调用完成之前执行相同的操作,那么我们将调用完成处理程序两次。

最好,我们以某种方式取消内部管道,因此我们只执行具有最新事件的完成处理程序。

当新事件沿着管道进入管道时,我如何“取消”该内部管道(由 dataTaskPublisher 启动的管道)而不拆除外部管道?

rob*_*off 5

你不想flatMap。你要switchToLatest。将您的更改flatMap为普通map,然后.switchToLatest()在其后添加。因为switchToLatest需要匹配失败类型,您可能还需要使用mapError. 该decode操作会产生故障类型Error,这样你就可以mapErrorError

例子:

state
    .publisher /* sends whenever 'state' updates behind the scenes */
    .debounce(for: 1.0, scheduler: DispatchQueue.main)
    .map { makeURLRequest(from: $0) }
    .map({ someRequest in
        URLSession.shared.dataTaskPublisher(for: someRequest)
            .map { $0.data }
            .decode(type: MyResponseType.self, decoder: JSONDecoder())
    })
    .mapError { $0 as Error }
    .switchToLatest()
    .sink(
        receiveCompletion: ({ (completion) in
            print(completion)
            /// cancelled
        }),
        receiveValue: ({ (output) in
            print(output)
            /// go show my results
            /// Ideally, this is only called when the most recent API call finishes!
        }))
    .store(in: &cancellables)
Run Code Online (Sandbox Code Playgroud)