iosswiftreactive-cocoareactive-cocoa-3

Multicasting in ReactiveCocoa 3 and ReactiveCocoa 4


Let's say I have a function that returns a SignalProducer<AnyObject?, NSError> and I want to bind the producer to multiple MutableProperty<String>. So, something like this:

let foo = SignalProducer<AnyObject?, NSError>(value: nil)
let someProperty1 = MutableProperty<String>("")
let someProperty2 = MutableProperty<String>("")

someProperty1 <~ foo
    .flatMapError { _ in
        SignalProducer<AnyObject?, NoError>.empty
    }
    .map { _ in
        return "test"
    }

// someProperty2 <~ foo etc...

In order to avoid my function (e.g. some network stuff) being run multiple times I would need to use multicasting. As far as I can tell from the CHANGELOG, startWithSignal is the operator to use for this. However I can't seem to figure out how to do this in a declarative manner.

So, one approach could be to make the binding in the closure of the startWithSignal:

foo.startWithSignal { signal, disposable in
    someProperty1 <~ signal
        .map { _ in
            return "test"
        }

    // someProperty2 <~ signal etc...
}

However this will obviously fail because we need to get rid of the NSError part. Because we're giving a Signal (opposed to a SignalProducer), we cannot use flatMapError (in RAC4, catch in RAC3). And I do not see how mapError can do this for us? Lastly, I'm not even sure that this is the proper way to handle multicasting in RAC3/RAC4?

Any help is much appreciated.


Solution

  • Use flatMapError (and any other operators that must take a SignalProducer argument) before starWithSignal

    let fooIgnoreError = foo
        .flatMapError { _ in
            SignalProducer<AnyObject?, NoError>.empty
        }
    
    
    fooIgnoreError.startWithSignal { signal, disposable in
        someProperty1 <~ signal.map { _ in "test" }
        someProperty2 <~ signal.map { _ in "test2" }
    }
    

    If the fooIgnoreError is started only once, your underlying signal producer foo is guaranteed to be started only once too.