我试图使我的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)
答案 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)
我会给您一些建议,我认为这些建议将来会对您有所帮助。
尽可能避免使用Observable.create
,这是可观察对象的“蛮力”创造,它根本无法处理背压,您必须自己实施,这不是一件容易的事。
通常,对于HTTP api调用,您不需要Observable,应使用Single
或Completable
,因为您期望服务器仅提供一个响应,而不是响应流。 / p>
您应该注意strong self
中的onNext/on...
,作为经验法则,如果预订观察者的类具有处理包,则应使用{{1} }。
现在对于您的特殊情况,如果您只需要一对观察者(获取并发送评论),我认为队列有点过大了。您只需在“获取”观察器的weak self
方法上调用评论注释观察器(如果有)。每当触发“ onNext”事件时,就会调用“下一步执行”。
如果您仍然需要一个队列,我将使用do(onNext:)
,该队列仅使操作排队,并具有类似OperationQueue
的方法,该方法将在每次操作完成时触发。这样,您只需订阅一次并入队多次,但这可能无法满足您的需求。
答案 2 :(得分:0)
一旦两个可观察对象都发出了信号,我将使用 .combineLatest()产生一个事件。参见http://rxmarbles.com/#combineLatest