iosreactive-cocoareactive-swift

How to map a completed event to an interrupt event when take(duringLifetimeOf:) happened in ReactiveSwift


For example, I want to send a request in my viewModel, if the viewModel is dealloc. The request signal should send interrupt event.

This is my code

func request() -> SignalProducer<Data, Error> {
    let request: SignalProducer<Data, Error> = ..... (This signal is from another module)
    return request.take(duringLifetimeOf: self)
}

This code will send a completed event instead of an interrupt event when self is dealloc. Because take(duringLifetimeOf:) API said:

Forward events from self until object deinitializes, at which point the returned producer will complete.

If I am the caller of this request(). I want to know whether my request is done. If the request is canceled due to the "self" being dealloc . Then I will get a completed event. This is not reasonable.

Is my thought right about mapping the completed event to the interrupt event?

What to do if my thought is right?


Solution

  • I've found that caring about the distinction between completed and interrupted events is often an anti-pattern, and there may be a better way to do what you are trying to do if you can share how exactly you're consuming the request() function.

    That said, here's a little custom operator that I think will do what you are trying to do:

    extension SignalProducer {
        func interrupt(after lifetime: Lifetime) -> SignalProducer<Value, Error> {
            return SignalProducer<Value, Error> { observer, innerLifetime in
                innerLifetime += self.start(observer)
                innerLifetime += lifetime.observeEnded(observer.sendInterrupted)
            }
        }
    }
    

    Then you can do this instead of using take(duringLifetimeOf:):

    func request() -> SignalProducer<Data, Error> {
        let request: SignalProducer<Data, Error> = ..... (This signal is from another module)
        return request.interrupt(after: self.reactive.lifetime)
    }