错误后如何继续订阅发布者? [英] How to continue subscribing to publisher after error?

查看:43
本文介绍了错误后如何继续订阅发布者?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试建立一个发布者,该发布者将发布一组整数,并且有时可能会失败.稍作设计,但希望能说明原理.下面的示例.

I am trying to set up a publisher that will publish a set of integers and at some point may fail. It's slightly contrived but hopefully illustrates principle. Example below.

enum NumberError: Int, Error {
   case isFatal, canContinue
}

struct Numbers {
    let p = PassthroughSubject<Int, NumberError>()

    func start(max: Int) {

        let errorI = Int.random(in: 1...max)
        for i in (1...max) {
            if errorI == i {
                p.send(completion: .failure(NumberError.canContinue))
            } else {
                p.send(i)
            }
        }
        p.send(completion: .finished)

    }
}

然后我使用以下方式订阅:

I then subscribe using:

let n = Numbers()
let c = n.p
    .catch {_ in return Just(-1)}

    .sink(receiveCompletion: {result in
        switch result {
        case .failure:
            print("Error")
        case .finished:
            print("Finished")
        }
    }, receiveValue: {
        print($0)
    })

n.start(max: 5)

此方法的工作原理是将错误替换为-1,但我想继续接收值.有人知道这是否可能吗?阅读并环顾四周,似乎可以选择flatMap,但是我无法确定要在闭包中使用哪个发布者?任何帮助表示赞赏.

This works in that it replaces errors with -1 but I would then like to continue receiving values. Does anyone know if this is possible? Having read and looked around it seems that flatMap may be the way to go but I can't work out what publisher to use in the closure? Any help much appreciated.

推荐答案

我认为您错误地认为 PassthroughSubject 可以在发布故障后发布更多输出.这不可以.调用 p.send(completion:...)后,对 p.send(...)的所有调用都将被忽略.此外,如果在调用 p.send(completion:...)之后订阅了 p p 将立即完成新的订阅,并且不发送任何输出.

I think you have an incorrect belief that a PassthroughSubject can publish more outputs after publishing a failure. It cannot. After you call p.send(completion: ...), any calls to p.send(...) will be ignored. Furthermore, if you subscribe to p after you call p.send(completion: ...), p will immediately complete the new subscription and not send any outputs.

因此,如果您想在以后发送更多值,则无法将错误作为 .failure 发送.而是将发布者的 Output 类型更改为 Result< Int,NumberError> ,将其 Failure 类型更改为 Never :

So you can't send your error as .failure if you want to send more values after. Instead, change your publisher's Output type to Result<Int, NumberError> and its Failure type to Never:

import Combine

enum NumberError: Int, Error {
   case isFatal, canContinue
}

struct Numbers {
    let p = PassthroughSubject<Result<Int, NumberError>, Never>()

    func start(max: Int) {
        let bad = (max + 1) / 2
        for i in (1...max) {
            if bad == i {
                p.send(.failure(NumberError.canContinue))
            } else {
                p.send(.success(i))
            }
        }
        p.send(completion: .finished)
    }
}

但是现在您不能使用 catch 来处理错误,因为它不会作为失败而通过.相反,您可以使用 map :

But now you can't use catch to handle the error, because it's not coming through as a failure. Instead, you can use map:

let n = Numbers()
let c = n.p
    .map({
        switch $0 {
        case .success(let i): return i
        case .failure(_): return -1
        }
    })
    .sink(receiveCompletion: {result in
        switch result {
        case .failure:
            print("Error")
        case .finished:
            print("Finished")
        }
    }, receiveValue: {
        print($0)
    })

n.start(max: 5)

输出:

1
2
-1
4
5
Finished

这篇关于错误后如何继续订阅发布者?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆