Steffen D. Sommer
Steffen D. Sommer

Reputation: 2926

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.

Upvotes: 2

Views: 557

Answers (2)

NachoSoto
NachoSoto

Reputation: 1743

I explained how to implement multicasting with an example here.

As for errors, you can make your property AnyProperty<Result<Value, Error>> to be able to forward errors. If you want the signal to terminate upon a failure, you can simply

signal.flatMapError { error in 
    fatalError("Error: \(error)") // or some other form of error handling, or simply ignoring the error?
    return .empty
}

Upvotes: 0

Cosyn
Cosyn

Reputation: 4987

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.

Upvotes: 0

Related Questions