RxSwift - 与Singleton不同类型的队列可观察对象

时间:2018-05-17 10:55:17

标签: swift queue rx-swift

我有一个Singleton类(实际上它会进行网络抓取,但在这里简化),有一些公共可用的功能。这些函数都返回Single<T>但不同类型。

看起来像这样:

class Singleton {
    static let shared = Singleton()
    private init() { }

    func doSomethingInt() -> Single<Int> {
        return Single.just(1)
            .delay(3, scheduler: MainScheduler.instance)
    }

    func doSomethingString() -> Single<String> {
        return Single.just("Wow")
            .delay(3, scheduler: MainScheduler.instance)
    }
}

当有人调用Singleton.shared.doSomthingInt()时,该函数应放在队列中,直到它通过队列才执行。队列中的下一个observable不应该在它完成之前的所有内容之前开始执行。理想情况下,Singleton将具有一个函数,该函数将延迟传递给它的每个函数的执行。像这样:

private func placeInQueue<T: Any>(operation: Single<T>) -> Single<T> {
    // place in some magic shared queue
    return operation
}

然后我可以在应该放入队列的函数的开头链接这个函数,如下所示:

func doSomethingString() -> Single<String> {
    let operation = Single.just("Wow")
        .delay(3, scheduler: MainScheduler.instance)
    return placeInQueue(operation)
}

我觉得这应该可以通过某种方式进行concat操作,但我还没有能够解决它。

任何线索?

1 个答案:

答案 0 :(得分:0)

我创建了这个类似乎正在工作:)

这可能是它运行的调度程序的问题。至少,如果我在队列中添加一些操作,每个操作在Sub ClearLowerThan() Dim c As Range, Rng As Range Dim LastRow As Long Dim ws As Worksheet: Set ws = Sheets("Sheet1") 'declare you worksheet, amend as required LastRow = ws.Cells(ws.Rows.Count, "A").End(xlUp).Row 'get the last row with data on Column A CompareVal = ws.Range("B1").Value 'get the value to compare against, in this case from cell B1 Set Rng = ws.Range("A1:A" & LastRow) 'set the range to compare against the value from B1 For Each c In Rng 'for each cell in the given range If c.Value < CompareVal Then c.ClearContents 'if value of cell is less than the value to compare against, clear the cell contents. Next End Sub 上都有3秒的延迟,我可以看到一些排队的操作最终在完成后大约3,5~4秒完成。之前的操作已经完成。对我来说这不是一个大问题:)

MainScheduler

以下是我如何使用它:

class ObservableQueue {
    init() { }

    private var queueArray = [(operation: Observable<Void>, id: Double)]()

    /// Adding the `operation` to an internal queue. Starts execution of the `operation` when all previous operations in the queue had sendt an stop event.
    func placeInQueue<T: Any>(_ operation: Single<T>) -> Single<T> {
        let operationId = createId()
        let queuedOperation = currentQueue()
            .flatMap { _ -> Single<T> in
                return operation
            }
            .do(
                onNext: { [weak self] _ in self?.removeFromQueue(id: operationId) },
                onError: { [weak self] _ in self?.removeFromQueue(id: operationId)
            })
        let queueableOperation = operation
            .map { _ in return () }
            .asObservable()
            .catchErrorJustReturn(())
        addToQueue(queueableOperation, id: operationId)
        return queuedOperation
    }

    private func createId() -> Double {
        var operationId: Double = Date().timeIntervalSince1970
        while (queueArray.contains { $0.id == operationId }) {
            operationId = Date().timeIntervalSince1970
        }
        return operationId
    }

    private func currentQueue() -> Single<Void> {
        var queue = queueArray.map{ $0.operation }
        if queue.isEmpty {
            queue = [Observable.just(())]
        }
        return Observable.concat(queue).takeLast(1).asSingle()
    }

    private func addToQueue(_ operation: Observable<Void>, id: Double) {
        queueArray.append((operation: operation, id: id))
    }

    private func removeFromQueue(id: Double) {
        guard let index = (queueArray.index { $0.id == id }) else { return }
        queueArray.remove(at: index)
    }
}

我希望这有助于某人:) 请随意将问题发布到此解决方案,或者如果您有任何更好的解决方案...