我正在尝试安排一系列图像下载。我想多次调用scheduleImagesDownload
,但是只有在上一次调用完成后,才能在downloadImages
中执行代码。
我正在尝试从相机中获取特定ID的图像,并下载了该ID的所有图像后,便想开始下载下一个ID的图像,依此类推。
我很难过,因为即使使用串行调度程序,在上一次下载完成之前,所有订阅都将立即被调用。我想知道是否有一种方法可以使用纯Rx,而不必使用信号量等。
提前谢谢!
func scheduleImagesDownload(flightId: String) -> Disposable {
let subscription = donwloadImages(flightId)
.subscribeOn(SerialDispatchQueueScheduler(qos: .background))
.subscribe(onCompleted: {
/// Finished downloading images for flight.
}, onError: { error in
/// Error downloading images for flight.
})
return subscription
}
func donwloadImages(_ flightId: String) -> Completable {
return Completable.create { completable in
/// Simulate querying the drone for images to download async and start downloading them.
DispatchQueue.global().async {
sleep(5) // Sleep to simulate downloading time.
completable(.completed) // Finished downloading.
}
return Disposables.create()
}
}
答案 0 :(得分:1)
用于链接队列中每个图像下载操作的关键操作符是ConcatMap
。
我已经根据您的要求编写了以下代码段。代码段几乎可以自我解释。
let flightIds: [String] = [] // Array holding flightIds
let disposeBag = DisposeBag()
func download() {
Observable.from(flightIds) // Convert array of flightIds into Observable chain
.flatMap(getImageURLs) // For each flightId, get array of image URLs to be downloaded
.flatMap(convertToImageURLObservable) // Convert array of image URLs into Observable chain
.concatMap(downloadImage) // Concate each url in observable chain so each image will be downloaded sequencially
.subscribeOn(SerialDispatchQueueScheduler(qos: .background)) // Scheduled entire chain on background queue
.subscribe()
.disposed(by: disposeBag)
}
/// Fetches image URLs for given flightId
func getImageURLs(_ flightId: String) -> Single<[URL]> {
return Single<[URL]>.create { single in
/// fetch & pass URLs in below array inside .success
single(.success([]))
return Disposables.create()
}
}
/// Convert array of image URLs into Observable chain
func convertToImageURLObservable(_ urls: [URL]) -> Observable<URL> {
return Observable.from(urls)
}
/// Downloads image for given URL
func downloadImage(_ url: URL) -> Completable {
return Completable.create { completable in
/// fetch image
DispatchQueue.global().async {
sleep(5) // Sleep to simulate downloading time.
completable(.completed) // Finished downloading.
}
return Disposables.create()
}
}
答案 1 :(得分:0)
我相信这就是您想要的。基本上,您会创建一个从摄像机检索到的所有ID的数组/集合。然后在每次完成操作时,删除集合中的一个元素,然后重新启动该过程,直到集合为空。
var cameraIds: Set<String>()
func scheduleImagesDownload(flightId: String) -> Disposable {
let subscription = donwloadImages(flightId)
.subscribeOn(SerialDispatchQueueScheduler(qos: .background))
.subscribe(onCompleted: {
if let nextFlightId = cameraIds.first {
cameraIds.removeFirst()
scheduleImagesDownload(flightId: nextFlightId)
} else {
// Finished downloads for all cameraIds and images
}
}, onError: { error in
/// Error downloading images for flight.
})
return subscription
}