ReactiveCocoa 4在SignalProducer
类then
上有一个等待生产者完成的方法,并将其替换为另一个生产者,如下所示:
someProducer.then(replacementProducer)
。
然而我想要的是一个等待原始生成器出错然后用第二个生成器替换它的方法(在完成事件上什么都不做)。
then
实现为(注意不转发下一个事件):
public func then<U>(replacement: SignalProducer<U, Error>) -> SignalProducer<U, Error> {
let relay = SignalProducer<U, Error> { observer, observerDisposable in
self.startWithSignal { signal, signalDisposable in
observerDisposable.addDisposable(signalDisposable)
signal.observe { event in
switch event {
case let .Failed(error):
observer.sendFailed(error)
case .Completed:
observer.sendCompleted()
case .Interrupted:
observer.sendInterrupted()
case .Next:
break
}
}
}
}
return relay.concat(replacement)
}
我想要的看起来很相似,除非失败,而不是发送错误,它会发送一个完整的信号。更具体地说,switch语句将改为:
signal.observe { event in
switch event {
case .Failed:
observer.sendCompleted()
case .Completed, .Next: break
case .Interrupted:
observer.sendInterrupted()
}
}
}
我的问题如下:
1)这有效吗?它按照我的预期工作,替换信号仅在第一个信号出错时才开始。 2)有没有更好的方法来做错误信息不会丢失?
我将使用它的一个示例是两步验证过程:
self.verifyToken(token).failed(self.revalidateSession())
如果令牌验证成功,一切都很好,无需重新验证。如果失败,则需要进行重新验证。
编辑:
我更改了信号观察块,这样如果第一个信号没有错误就完成了,它会用startWithComplete
启动替换信号,这样完成事件就会在链中转发,而不会触发信号的任何动作。
这样可以很容易地做到这一点:
self.verify(token).failed(self.refreshSession(token)).then(self.fetchUserForToken(token))
其中then
被链接,只有在verify
或refreshSession
成功时才会执行。
signal.observe { event in
switch event {
case .Failed:
observer.sendCompleted()
case .Completed:
replacement.startWithCompleted {}
case .Next: break
case .Interrupted:
observer.sendInterrupted()
}
}
}
答案 0 :(得分:1)
1)这有效吗?
没有。如果验证信号生成器发送正常值并完成,则替换信号生成器确实启动(通过startWithCompleted
调用)但不会产生任何结果(因为您没有观察到startWithCompleted
闭包中的任何内容,并且内部replay
信号生成器永远不会终止。
2)有更好的方法吗?
您可以使用flatMapError
运算符,这样您也可以获取错误信息。
self.verify(token)
.map { _ in () }
.flatMapError { error in
return self.refreshSession(token).map { _ in () }
}
注意,如果map { _ in () }
生成器和veriy
生成器生成相同类型的值,则可以省略两个refreshSession
。