I'm trying to wrap an API call that initializes an object after a network request. I don't want the network request to happen for every new observer, so as I understand it, I shouldn't be using SignalProducer
. However, by using a single Signal
, only the first usage of it will receive a next
event, while any newer subscribers will never receive the current value. How should I be doing this? I'm probably doing something fundamentally wrong with RAC.
extension SparkDevice {
static func createMainDeviceSignal() -> Signal<SparkDevice, NSError> {
return Signal {
sink in
SparkCloud.sharedInstance().getDevices { (sparkDevices: [AnyObject]!, error: NSError!) -> Void in
if let error = error {
sink.sendFailed(error)
}
else {
if let devices = sparkDevices as? [SparkDevice] {
if devices.count > 0 {
sink.sendNext(devices[0])
}
}
}
}
return nil
}
}
}
class DeviceAccess {
let deviceSignal: Signal<SparkDevice, NSError>
init() {
self.deviceSignal = SparkDevice.createMainDeviceSignal()
}
}
I considered using MutableProperty
, but that seems to require a default property, which doesn't seem to make sense for this.
How should I actually be going about this?
What you need is multicasting. However,
ReactiveCocoa
3/4 does not offer a simple way to do that (as opposed to Rx) because they often lead to a ton of complexity.Sometimes it is really necessary, as in your example, and it can be easily implemented using a
PropertyType
.I'd start by creating the cold signal that makes the request. That has to be a
SignalProducer
:If you were to expose this as is, the side effects would occur every time this producer is
start
ed. Tomulticast
these values you can wrap it in a property and expose theproperty
'sproducer
instead:Now
DeviceAccess.deviceProducer
would replay the values emitted by the underlying producer instead of repeating side-effects. Note however that it's not lazy: the underlyingSignalProducer
would be started right away.