Why doesn't SignalProducer return a Signal?

2019-04-26 20:24发布

问题:

I feel like I understand all of the basic components of ReactiveCocoa (conceptually), by understanding how to connect all of the pieces together is still a bit confusing.

For example, after reading about Signal, I fully expected SignalProducer to just have one start() method which returned a Signal, which you would use like so:

mySignalProducer.start().observe(myObserver)

Instead, you have to pass an observer into start(), and SignalProducer calls observe() for you:

mySignalProducer.start(myObserver)

This means that the interface of SignalProducer is much larger (more to understand), because all of the variations on observe() have to be duplicated on start() (e.g. startNext(), etc).

I think there are two possibilities here:

  1. There are technical reasons why start() can't simply return a Signal
  2. I misunderstand the SignalProducer conceptually, leading to wonky expectations of its interface

If 1 is the case, I'm guessing that has something to do with memory management and disposables which I don't fully understand yet.

I'm more worried that 2 is the case. Internally, my understanding of SignalProducer is basically mapped to the concept of a Factory, e.g.:

mySignalFactory.createSignal().observe(myObserver)

which is why I'm surprised we don't find a start() which returns a Signal.

I would be hugely appreciative if the community could shed some light here.

Thanks!

回答1:

I think the main reason is some events can be sent immediately when the producer starts.

For example, if you don't like the start series interface, and want to get a signal directly when start:

extension SignalProducer {
    func getSignalFromStart() -> Signal<Value, Error> {
        var signal: Signal<Value, Error>!
        startWithSignal{ innerSignal, _ in
            signal = innerSignal
        }
        return signal
    }
}

Then you can miss some events. Try this:

// When property.producer starts, it will send its current value immediately
let property = MutableProperty(1)

property.producer.getSignalFromStart().observeValues { value in
    print("getSignalFromStart \(value)") // maybe not what you want, only gets 2
}

property.producer.startWithValues { value in
    print("normal start \(value)") // this normally gets 1 and 2
}

property.value = 2