swift - 信号 : Collect values over time interval

标签 swift swift3 reactive-cocoa reactive-swift

这可能是一个微不足道的问题,但我无法为这个看似简单的任务找到解决方案。由于我是 ReactiveSwift 和响应式编程的新手,所以我可能会错过一些明显的东西。

基本上我想做的是这样的:

signal.collect(timeInterval: .seconds(5))

我想从信号中收集特定时间段内的所有值。生成的信号将每 x 秒产生一个事件,其中包含从第一个信号收集的事件数组。

在 ReactiveSwift 中执行此操作的最佳方法是什么?

最佳答案

ReactiveSwift 中没有用于此任务的内置运算符。相反,您可以使用以下方法编写扩展:

import Foundation
import ReactiveSwift
import Result
public extension Signal {
    public func completeAfter(after: TimeInterval, onScheduler : DateSchedulerProtocol = QueueScheduler() ) -> Signal {
        let pipe : (Signal<(), NoError>, ReactiveSwift.Observer<(), NoError>) = Signal<(), NoError>.pipe()
        onScheduler.schedule(after: Date(timeIntervalSinceNow: after)) {
            pipe.1.sendCompleted()
        }
        return Signal { observer in
            return self.observe { event in
                switch event {
                case let .value(value):
                    observer.send(value: value)
                case .completed:
                    observer.sendCompleted()
                case let .failed(error):
                    observer.send(error: error)
                case .interrupted:
                    observer.sendInterrupted()
                }
            }
        }.take(until: pipe.0)
    }

    public func collectUntil(until: TimeInterval) -> Signal<[Value], Error> {
        return self.completeAfter(after: until).collect()
    }
}

然后使用signal.collectUntil(5)方法。

另一种方法是使用 ReactiveSwift 中的 timer 函数。示例(添加到相同的扩展名,如上所述):

public func collectUntil2(until: TimeInterval) -> Signal<[Value], Error> {
    var signal: Signal<(), NoError>? = nil
    timer(interval: until, on: QueueScheduler()).startWithSignal { innerSignal, _ in
        signal = innerSignal.map { _ in () }.take(first: 1)
    }
    return self.take(until: signal!).collect()
}

但是,我不喜欢这种方法,因为它是 SignalProducer 类型提取内部信号的伪造特性。

Signal 类型本身也有 timeout 功能,但是由于它会产生错误,因此很难使用。如何使用它的示例(仍然,添加到相同的扩展):

public func completeOnError() -> Signal<Value, Error> {
    return Signal { observer in
        return self.observe { event in
            switch(event) {
            case .value(let v): observer.send(value: v)
            case .failed(_): observer.sendCompleted()
            case .interrupted: observer.sendInterrupted()
            case .completed: observer.sendCompleted()
            }
        }
    }
}

public func collectUntil3(until: TimeInterval) -> Signal<[Value], Error> {
    return self
        .timeout(after: until,
                 raising: NSError() as! Error,
                 on: QueueScheduler())
        .completeOnError()
        .collect()
}

附言通过选择 3 个选项中的任何一个,请注意传递正确的调度程序或使用正确的调度程序对您的解决方案进行参数化。

关于swift - 信号 : Collect values over time interval,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42694045/

相关文章:

swift - 为什么 Xcode 8.3.2 在编辑时不立即显示语法错误

ios - 如何在 self.dismiss block 中推送 UIViewController?

ios - 如何在 SignalProducer 上映射值和错误

ios - 将 Float 数组写入二进制文件并快速读取

ios - 在 Swift 中显示 reverseGeocoder 结果的闭包

ios - 如何使用 Swift 使用此代码片段为 iOS 应用程序初始化 SDK?

ios - 如何查看带有 NohanaImagePicker pod 文件的图像?

ios - react swift : Observe Managed Object changes with MutableProperty

ios - 如何绑定(bind) Realm 对象的变化?

swift - 当值不是 nil 时,在展开可选值时意外发现 nil