如何观察信号并立即接收到"next"事件(如果已经发生)? [英] How do I observe a signal and immediately receive a `next` event if it has already occured?

查看:81
本文介绍了如何观察信号并立即接收到"next"事件(如果已经发生)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试包装一个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这些值,您可以将其包装在属性中,并公开propertyproducer:

If you were to expose this as is, the side effects would occur every time this producer is started. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆