[英]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)
}
}
我會給您一些建議,我認為它將對您將來有所幫助。
盡可能避免Observable.create
,這是Observable.create
的“強力”創建,它根本無法處理背壓,您必須自己實現,這並不容易。
通常對於HTTP api調用,您不需要Observable,應該使用Single
或Completable
因為您期望服務器僅提供一個響應,而不是響應流。
您應該注意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.