Rxswift map + concat并行

时间:2016-06-10 22:35:55

标签: swift rx-swift

此Observable正在执行以下

  • 鉴于源可观察
  • 我们使用map执行一些异步工作
  • 我们使用concat按顺序返回异步工作的结果

以下是返回所需的结果,但我想开始 异步工作并行。

使用Rx执行此操作的正确方法是什么?

Error in as.data.frame.default(x[[i]], optional = TRUE) : 
  cannot coerce class ""expression"" to a data.frame

这个产品

import RxSwift

func delay(time: Int, closure: () -> Void) {
  dispatch_after(
    dispatch_time(DISPATCH_TIME_NOW, Int64(time * Int(NSEC_PER_SEC))),
    dispatch_get_main_queue(), closure)
}

func doAsyncWork(value: Int, desc: String, time: Int) -> Observable<Int> {
  return Observable.create() { (observer) -> Disposable in
    print(desc)
    delay(time) {
      observer.onNext(value)
      observer.onCompleted()
    }
    return NopDisposable.instance
  }
}

let seq = Observable
  .of(1, 2, 3, 4, 5)
  .map { (n) -> Observable<Int> in
    return doAsyncWork(n,
      desc: "start \(n) - wait \(5 - n)",
      time: 6 - n
    )
  }
  .concat()

let sharedSeq = seq.shareReplay(0)
sharedSeq.subscribeNext { print("=> \($0)") }
sharedSeq.subscribeCompleted { print("=> completed") }

所需的输出是

//start 1 - wait 4
// => 1
//start 2 - wait 3
// => 2
//start 3 - wait 2
// => 3
//start 4 - wait 1
// => 4
//start 5 - wait 0
// => 5

4 个答案:

答案 0 :(得分:2)

这似乎无法确定这是最好的答案

import RxSwift

func delay(time: Int, closure: () -> Void) {
  dispatch_after(
    dispatch_time(DISPATCH_TIME_NOW, Int64(time * Int(NSEC_PER_SEC))),
    dispatch_get_main_queue(), closure)
}

func doAsyncWork(value: Int, desc: String, time: Int) -> Observable<Int> {
  return Observable.create() { (observer) -> Disposable in
    print(desc)
    delay(time) {
      observer.onNext(value)
      observer.onCompleted()
    }
    return NopDisposable.instance
  }
}

let seq = Observable
  .of(1, 2, 3, 4, 5)
  .map { (n) -> Observable<Int> in
    let o = doAsyncWork(n,
      desc: "start \(n) - wait \(5 - n)",
      time: 6 - n
    ).shareReplay(1)
    o.subscribe()
    return o.asObservable()
  }
  .concat()

let sharedSeq = seq.shareReplay(0)
sharedSeq.subscribeNext { print("=> \($0)") }
sharedSeq.subscribeCompleted { print("=> completed") }

答案 1 :(得分:1)

您想要的输出&#34;似乎不同意你想要Observable并行开始&#34;并且延迟他们的元素,以及&#34; 5&#34;没有延迟,&#34; 4&#34;延迟1秒,&#34; 3&#34;有2秒的延迟等等。

我认为你正在寻找这个输出:

start 1 - wait 4
start 2 - wait 3
start 3 - wait 2
start 4 - wait 1
start 5 - wait 0
5
4
3
2
1

这可以用来做到这一点:

Observable.range(start: 1, count: 5)
    .flatMap { n -> Observable<Int> in
        let waitInterval = 5 - n
        print("start \(n) - wait \(waitInterval)")
        return Observable.just(n)
            .delaySubscription(RxTimeInterval(waitInterval), scheduler: MainScheduler.instance)
    }
    .subscribeNext { i in
        print(i)
    }
    .addDisposableTo(disposeBag)

如果您想要其他内容,您可以轻松调整此代码段以实现目标。

答案 2 :(得分:0)

这对你现在没有帮助,但也许它将来会帮助别人。

您正在寻找的运营商名为concatMap。但是,目前它在RxSwift中不存在。

目前存在已关闭的PR here

答案 3 :(得分:0)

这不能按预期工作的原因是concat一次订阅源observables 一个,等待第一个完成订阅第二个之前等等。

在RxJava中有concatEager,它可以满足您的需求 - 在开始时订阅所有源,同时仍然保留顺序。但似乎不是在Swift中。

你能做的就是用索引,flatMap,索引排序和解压缩来拉链每个项目。