[英]How do I observe a signal and immediately receive a `next` event if it has already occured?
I'm trying to wrap an API call that initializes an object after a network request. 我正在尝试包装网络请求后初始化对象的API调用。 I don't want the network request to happen for every new observer, so as I understand it, I shouldn't be using
SignalProducer
. 我不希望每个新观察者都发生网络请求,因此据我了解,我不应该使用
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. 但是,通过使用单个
Signal
,只有它的第一次使用会收到next
事件,而任何新订阅者将永远不会收到当前值。 How should I be doing this? 我应该怎么做? I'm probably doing something fundamentally wrong with RAC.
我可能在做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. 我考虑过使用
MutableProperty
,但这似乎需要一个默认属性,这似乎没有任何意义。
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. 但是,
ReactiveCocoa
3/4并没有提供一种简单的方法(与Rx相对),因为它们通常会导致大量的复杂性。
Sometimes it is really necessary, as in your example, and it can be easily implemented using a PropertyType
. 有时确实很必要,如您的示例所示,并且可以使用
PropertyType
轻松实现。
I'd start by creating the cold signal that makes the request. 我将从创建发出请求的冷信号开始。 That has to be a
SignalProducer
: 那必须是
SignalProducer
:
private func createMainDeviceSignalProducer() -> SignalProducer<SparkDevice, NSError> {
return SignalProducer { observer, _ in
....
}
}
If you were to expose this as is, the side effects would occur every time this producer is start
ed. 如果你要原样公开此,副作用会发生每到这个制片人是时候
start
编辑。 To multicast
these values you can wrap it in a property and expose the property
's producer
instead: 要
multicast
这些值,您可以将其包装在属性中,然后公开该property
的producer
:
public final class DeviceAccess {
public let deviceProducer: SignalProducer<SparkDevice, NoError>
private let deviceProperty: AnyProperty<SparkDevice?>
init() {
self.deviceProperty = AnyProperty(
initialValue: nil, // we can use `nil` to mean "value isn't ready yet"
producer: SparkDevice.createMainDeviceSignal()
.map(Optional.init) // we need to wrap values into `Optional` because that's the type of the property
.flatMapError { error in
fatalError("Error... \(error)") // you'd probably want better error handling
return .empty // ignoring errors, but you probably want something better.
}
)
self.deviceProducer = deviceProperty
.producer // get the property producer
.ignoreNil() // ignore the initial value
}
}
Now DeviceAccess.deviceProducer
would replay the values emitted by the underlying producer instead of repeating side-effects. 现在,
DeviceAccess.deviceProducer
将重播底层生产者发出的值,而不是重复产生副作用。 Note however that it's not lazy : the underlying SignalProducer
would be started right away. 但是请注意,这并不懒惰 :底层的
SignalProducer
将立即启动。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.