如果信号已经发生,如何观察信号并立即收到`next`事件?

时间:2015-11-26 20:32:49

标签: swift swift2 reactive-programming reactive-cocoa reactive-cocoa-3

我试图在网络请求后打包初始化对象的API调用。我不希望每个新观察者都发生网络请求,因此据我所知,我不应该使用SignalProducer。但是,通过使用单个Signal,只有第一次使用它才会收到next事件,而任何新订阅者都永远不会收到当前值。我该怎么做?我可能在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,但这似乎需要一个默认属性,这似乎对此没有意义。

我该怎么做呢?

1 个答案:

答案 0 :(得分:6)

您需要的是多播。但是,ReactiveCocoa 3/4并没有提供一种简单的方法(与Rx相反),因为它们通常会导致大量的复杂性。

有时真的有必要,就像你的例子一样,并且可以使用PropertyType轻松实现。

我首先创建发出请求的冷信号。那必须是SignalProducer

private func createMainDeviceSignalProducer() -> SignalProducer<SparkDevice, NSError> {
    return SignalProducer { observer, _ in
        ....
    }
}

如果您按原样公开,则每次此生产者start编辑时都会出现副作用。要multicast这些值,您可以将其包含在属性中,并公开property的{​​{1}}代替:

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 } } 将重放底层生成器发出的值,而不是重复的副作用。但请注意,它不是 lazy :基础DeviceAccess.deviceProducer将立即启动。