簡體   English   中英

RxSwift。 隨后執行單獨的可觀察對象

[英]RxSwift. Execute separate Observables sequently

我試圖使我的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)

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. 盡可能避免Observable.create ,這是Observable.create的“強力”創建,它根本無法處理背壓,您必須自己實現,這並不容易。

  2. 通常對於HTTP api調用,您不需要Observable,應該使用SingleCompletable因為您期望服務器僅提供一個響應,而不是響應流。

  3. 您應該注意onNext/on...內的strong self ,作為經驗法則,如果訂閱觀察者的類具有處理包,則應使用weak self

現在針對您的特殊情況,如果您只需要一對觀察者(獲取並發送評論),我認為隊列有點過大了。 您只需在“獲取”觀察器的do(onNext:)方法上調用評論注釋觀察器(如果有)。 每當觸發“ onNext”事件時,就會調用“下一步執行”。

如果您仍然需要隊列,則可以使用僅使操作入隊的OperationQueue ,並具有類似observeOperationchanges() -> Observeble<Operation>該方法將在每次操作完成時觸發。 這樣,您只需訂閱一次並入隊多次,但這可能無法滿足您的需求。

一旦兩個可觀察對象都發出了某些信號,我將使用.combineLatest()產生一個事件。 參見http://rxmarbles.com/#combine最新

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM