2

我想在我的应用程序中处理一系列网络调用。每个调用都是异步的,flatMap()看起来像是正确的调用。但是,flatMap同时处理所有参数,我需要顺序调用——下一个网络调用只有在前一个网络调用完成后才开始。我查找了 RxSwift答案,但它需要concatMapCombine 没有的运算符。这是我正在尝试做的事情的粗略轮廓,但同时flatMap触发myCalls

Publishers.Sequence(sequence: urls)
  .flatMap { url in
    Publishers.Future<Result, Error> { callback in 
        myCall { data, error in 
            if let data = data {
                callback(.success(data))
            } else if let error = error {
                callback(.failure(error))
            }
        }
    }
  }
4

2 回答 2

3

在操场上尝试了一段时间后,我相信我找到了解决方案,但是如果您有更好的想法,请分享。解决方案是添加maxPublishers参数flatMap并将值设置为max(1)

Publishers.Sequence(sequence: urls)
  .flatMap(maxPublishers: .max(1)) // <<<<--- here
  { url in 
    Publishers.Future<Result, Error> { callback in 
      myCall { data, error in 
        if let data = data {
          callback(.success(data))
        } else if let error = error {
          callback(.failure(error))
        }
      }
    }
  }
于 2019-06-18T21:16:51.590 回答
1

您还可以在 observable 上使用prepend(_:) 方法来创建连接序列,我想这与RxSwiftObservable.concat(:) 中的类似。

这是一个简单的示例,我试图模拟您的用例,其中我有几个不同的序列,然后是另一个序列。

func dataTaskPublisher(_ urlString: String) -> AnyPublisher<(data: Data, response: URLResponse), Never> {
    let interceptedError = (Data(), URLResponse())
    return Publishers.Just(URL(string: urlString)!)
                        .flatMap {
                            URLSession.shared
                                        .dataTaskPublisher(for: $0)
                                        .replaceError(with: interceptedError)
                        }
                        .eraseToAnyPublisher()
}

let publisher: AnyPublisher<(data: Data, response: URLResponse), Never> = Publishers.Empty().eraseToAnyPublisher()


for urlString in [
    "http://ipv4.download.thinkbroadband.com/1MB.zip",
    "http://ipv4.download.thinkbroadband.com/50MB.zip",
    "http://ipv4.download.thinkbroadband.com/10MB.zip"
    ] {
        publisher = publisher.prepend(dataTaskPublisher(urlString)).eraseToAnyPublisher()
}

publisher.sink(receiveCompletion: { completion in
    print("Completed")
}) { response in
    print("Data: \(response)")
}

在这里,prepend(_:)运算符为序列添加前缀,因此,前置序列首先开始,完成,下一个序列开始。

如果您运行下面的代码,您应该会看到首先下载了 10 MB 的文件,然后是 50 MB,最后是 1 MB,因为最后一个前置文件首先开始,依此类推。

运算符的其他变体prepend(_:)采用数组,但这似乎不是按顺序工作的。

于 2019-06-18T23:26:13.173 回答