如何观察信号并立即接收到"next"事件(如果已经发生)? [英] How do I observe a signal and immediately receive a `next` event if it has already occured?
问题描述
我正在尝试包装一个API请求,该请求将在网络请求后初始化一个对象.我不希望每个新观察者都发生网络请求,因此据我了解,我不应该使用SignalProducer
.但是,通过使用单个Signal
,只有第一次使用它会收到一个next
事件,而任何较新的订阅者将永远不会收到当前值.我应该怎么做?我可能在做RAC方面的根本错误.
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()
}
}
我考虑使用MutableProperty
,但这似乎需要一个默认属性,对此似乎没有意义.
I considered using MutableProperty
, but that seems to require a default property, which doesn't seem to make sense for this.
实际上我应该怎么做?
推荐答案
您需要的是多播.但是,ReactiveCocoa
3/4并没有提供一种简单的方法(与Rx相对),因为它们通常会导致大量的复杂性.
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.
有时确实确实有必要,例如您的示例,并且可以使用PropertyType
轻松实现.
Sometimes it is really necessary, as in your example, and it can be easily implemented using a PropertyType
.
我将从创建发出请求的冷信号开始.必须是SignalProducer
:
I'd start by creating the cold signal that makes the request. That has to be a SignalProducer
:
private func createMainDeviceSignalProducer() -> SignalProducer<SparkDevice, NSError> {
return SignalProducer { observer, _ in
....
}
}
如果按原样公开此内容,则每次对该生产者进行start
处理时,都会发生副作用.要multicast
这些值,您可以将其包装在属性中,并公开property
的producer
:
If you were to expose this as is, the side effects would occur every time this producer is start
ed. To multicast
these values you can wrap it in a property and expose the property
's producer
instead:
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
}
}
现在DeviceAccess.deviceProducer
将重播底层生产者发出的值,而不是重复出现副作用.但是请注意,这不是 lazy :基础SignalProducer
将立即启动.
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 underlying SignalProducer
would be started right away.
这篇关于如何观察信号并立即接收到"next"事件(如果已经发生)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!