【问题标题】:How do I observe a signal and immediately receive a `next` event if it has already occured?如果信号已经发生,我如何观察信号并立即接收到“下一个”事件?
【发布时间】:2016-03-01 00:25:20
【问题描述】:

我正在尝试封装一个在网络请求后初始化对象的 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,但这似乎需要一个默认属性,这似乎没有意义。

我应该怎么做呢?

【问题讨论】:

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


    【解决方案1】:

    您需要的是多播。然而,ReactiveCocoa 3/4 并没有提供一种简单的方法来做到这一点(与 Rx 不同),因为它们通常会导致大量的复杂性。

    有时确实有必要,就像您的示例一样,并且可以使用PropertyType 轻松实现。

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

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

    如果您按原样公开此内容,则每次此生产者为started 时都会出现副作用。对于multicast 这些值,您可以将其包装在一个属性中,并改为公开propertyproducer

    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 将重放底层生产者发出的值,而不是重复副作用。但请注意,它不是惰性:底层的SignalProducer 将立即启动。

    【讨论】:

    • 通过这种方法,您可以评论访问 DeviceAccess.deviceProducer。但是应该如何访问呢?单身狗? DeviceAccess.sharedInstance.deviceProducer.startWithNext{...} 所有想要观察相同结果的实例以及它应该如何重新加载 SparkDevice 每当它发生变化时? (从后端再次获取)
    猜你喜欢
    • 1970-01-01
    • 2014-03-27
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多