RxSwift。随后执行单独的可观察对象

时间:2018-09-28 10:29:19

标签: ios swift synchronization rx-swift reactive

我试图使我的Observables仅在先前的Observable完成时才执行。我不能使用flatMap,因为可以从不同的地方调用订阅,并且此Observables没有相互连接。具体来说:我让CollectionView从服务器加载更多内容,并且该用户在CollectionView仍在加载其批处理时单击“发送评论”按钮2秒后。因此,我想等到CollectionView更新完成,然后再执行我的评论的发布请求。我创建了一个名为ObservableQueue的类,它的工作正常。但是我需要知道它是否存在诸如内存泄漏,死锁之类的问题,或者我只是缺少某些东西。在这里:

extension CompositeDisposable {

    @discardableResult
    func insert(disposeAction: @escaping () -> ()) -> DisposeKey? {
        return insert(Disposables.create(with: disposeAction))
    }

}

class ObservableQueue {

    private let lock = NSRecursiveLock()
    private let relay = BehaviorRelay(value: 0)
    private let scheduler = SerialDispatchQueueScheduler(internalSerialQueueName: "ObservableQueue.scheduler")

    func enqueue<T>(_ observable: Observable<T>) -> Observable<T> {
        return Observable.create({ observer -> Disposable in
            let disposable = CompositeDisposable()

            let relayDisposable = self
                .relay
                .observeOn(self.scheduler)
                .filter({ value -> Bool in
                    if value > 0 {
                        return false
                    }

                    self.lock.lock(); defer { self.lock.unlock() }

                    if self.relay.value > 0 {
                        return false
                    }

                    self.relay.accept(self.relay.value + 1)

                    disposable.insert {
                        self.lock.lock(); defer { self.lock.unlock() }
                        self.relay.accept(self.relay.value - 1)
                    }

                    return true
                })
                .take(1)
                .flatMapLatest { _ in observable }
                .subscribe { observer.on($0) }

            _ = disposable.insert(relayDisposable)

            return disposable
        })
    }

}

然后我可以像这样使用它:

let queue = ObservableQueue()

...

// first observable
let observable1 = Observable
    .just(0)
    .delay(5, scheduler: MainScheduler.instance)

queue
    .enqueue(observable1)
    .subscribe(onNext: { _ in
        print("here1")
     })
    .disposed(by: rx.disposeBag)

// second observable
let observable2 = Observable
    .just(0)
    .delay(5, scheduler: MainScheduler.instance)

queue
    .enqueue(observable2)
    .subscribe(onNext: { _ in
        print("here2")
    })
    .disposed(by: rx.disposeBag)

// third observable
let observable3 = Observable
    .just(0)
    .delay(5, scheduler: MainScheduler.instance)

queue
    .enqueue(observable3)
    .subscribe(onNext: { _ in
        print("here3")
    })
    .disposed(by: rx.disposeBag)

3 个答案:

答案 0 :(得分:2)

CLGeocoder具有相同的问题。根据该文档,当地理编码器方法正在处理先前的请求时,就无法像您尝试执行的那样调用其中一种地理编码器方法。在这个要点(https://gist.github.com/dtartaglia/64bda2a32c18b8c28e1e22085a05df5a)中,您将发现我在后台线程上进行了可观察的调用,并使用信号量保护了作业。这就是关键,您需要一个信号灯,而不是一个锁。

类似的事情应该对您有用:

class ObservableQueue {

    private let semaphore = DispatchSemaphore(value: 1)
    private let scheduler = ConcurrentDispatchQueueScheduler(qos: .userInitiated)

    func enqueue<T>(_ observable: Observable<T>) -> Observable<T> {
        let _semaphore = semaphore // To avoid the use of self in the block below
        return Observable.create { observer in
            _semaphore.wait()
            let disposable = observable.subscribe { event in
                switch event {
                case .next:
                    observer.on(event)
                case .error, .completed:
                    observer.on(event)
                }
            }
            return Disposables.create {
                disposable.dispose()
                _semaphore.signal()
            }
        }
        .subscribeOn(scheduler)
    }
}

答案 1 :(得分:0)

我会给您一些建议,我认为这些建议将来会对您有所帮助。

  1. 尽可能避免使用Observable.create,这是可观察对象的“蛮力”创造,它根本无法处理背压,您必须自己实施,这不是一件容易的事。

  2. 通常,对于HTTP api调用,您不需要Observable,应使用SingleCompletable,因为您期望服务器仅提供一个响应,而不是响应流。 / p>

  3. 您应该注意strong self中的onNext/on...,作为经验法则,如果预订观察者的类具有处理包,则应使用{{1} }。

现在对于您的特殊情况,如果您只需要一对观察者(获取并发送评论),我认为队列有点过大了。您只需在“获取”观察器的weak self方法上调用评论注释观察器(如果有)。每当触发“ onNext”事件时,就会调用“下一步执行”。

如果您仍然需要一个队列,我将使用do(onNext:),该队列仅使操作排队,并具有类似OperationQueue的方法,该方法将在每次操作完成时触发。这样,您只需订阅一次并入队多次,但这可能无法满足您的需求。

答案 2 :(得分:0)

一旦两个可观察对象都发出了信号,我将使用 .combineLatest()产生一个事件。参见http://rxmarbles.com/#combineLatest

相关问题