如何在 ReactiveSwift 中组合 Actions ("run the first enabled action from this list")

How to compose Actions in ReactiveSwift ("run the first enabled action from this list")

我有两个 Action 具有相同的 input/output/error 类型,我想将它们组合成一个 Action 运行两个启用的任何一个(与一个任意的决胜局,如果他们都是。

这是我第一次失败的尝试:

let addOrRemove: Action<MyInput, MyOutput, APIRequestError> = Action(enabledIf: add.isEnabled.or(remove.isEnabled)) { input in
    if add.isEnabled.value {
        return add.apply(input)
    } else {
        return remove.apply(input)
    }
}

这失败了,因为内部 add.apply(input) 看不到我检查了 add.isEnabled,所以它在错误类型周围包装了一个额外的 ActionError<> 层。 (这可能是合法的,因为我不确定这种方法的线程安全性如何,或者我们可能知道类型系统不知道的事情。)相应的类型错误是:

cannot convert return expression of type 'SignalProducer<MyOutput, ActionError<APIRequestError>>' to return type 'SignalProducer<MyOutput, APIRequestError>'

我应该怎么做?

Github 用户 @ikesyo provided the following answer on the ReactiveSwift issue I opened to ask the same question:

let producer: SignalProducer<MyOutput, ActionError<APIRequestError>>
if add.isEnabled.value {
    producer = add.apply(input)
} else {
    producer = remove.apply(input)
}
return producer.flatMapError { error in
    switch error {
    case .disabled: return .empty
    case let .producerFailed(inner): return SignalProducer(error: inner)
    }
}

如果他们出现在这里,我会很乐意将已接受的答案更改为他们的答案(归功于它所属的地方)。

警告:如果我正确阅读了这个答案,它并不是无懈可击的。如果 add 在包装 Actionapply()start() 之间从启用变为禁用,我们将得到 "success"(没有值,但是 .completed) 而不是我们应该得到的 .disabled。这对我的用例来说已经足够了,但是 YMMV。