RxSwift通过flatMaps链传播一个值

时间:2016-04-28 04:14:15

标签: swift rx-swift

所以我有一些RxSwift代码,我想要执行一系列异步操作,所有操作都是使用observable组成的。 flatMap是实现此目的的方法,并且它运行良好,但它似乎无法将变量传递到我能够找到的链中。一些伪代码最好地说明了这一点

假设有3个功能

class Connection {
    static func establish(address:String) -> Observable<Connection>
    func sendData(data:String) -> Observable<Int> // num bytes written or something
    func close() -> Observable<Void>
}

我想把它们称为链,这样我们就可以连接,发送,然后关闭。像这样的东西

Connection.establish(host)
    .flatMap{ connection in connection.sendData("foo") }
    .flatMap{ numBytes in ????.close() }
    .subscribeNext{ /* all done */ }

问题是flatMap没有在链中传递它的输入参数,因此传递给subscribeNext的闭包不能访问connection对象,并且这样就不能打电话了。

我可以像下面这样做一些可怕的黑客,但我真的不愿意!

var connection:Connection?
Connection.establish(host)
    .flatMap{ c in 
        connection = c
        return c.sendData("foo") 
    }
    .flatMap{ numBytes in connection!.close() }
    .subscribeNext{ /* all done */ }

在Rx的C#版本中,这是通过使用SelectMany的重载来解决的,该重载采用第二个闭包,它结合了2个值(通常是一个元组)然后 东西沿着链条传播。我把它写成RxSwfit的扩展,它的工作原理如下:

Connection.establish(host)
    .flatMap(
        { connection in connection.sendData("foo") },
        combine: { ($0, $1) }) // tupleify
    .flatMap{ (connection, numbytes) in connection.close() }
    .subscribeNext{ /* all done */ }

这一切都很好,但我的主要问题是 - 有没有更好的方法来实现这个内置于RxSwift目前的立场?

此外,编写此扩展方法并不简单也不容易。我基本上是通过复制/粘贴MiniRxSwift中的那个并重新修改它来从头开始重新实现FlatMap。如果我们必须编写此扩展,是否有更好的方法使用RxSwift构造实现它?

2 个答案:

答案 0 :(得分:1)

您可以在establish功能中执行此操作。它可能看起来像这样:

static func establish(address:String) -> Observable<Connection> {
    return Observable.create { observer in
        //create connection
        observer.onNext(connection)
        observer.onCompleted()

        return AnonymousDisposable { connection.close() }
    }
}

当您observer处置时,它也会关闭您的连接 我认为这是最好的选择之一。

但是,我们可以使用combineLatestflatMap或其他函数通过链传递连接。但这将是乏味的:)

回复Orion Edwards

  

不确定这会起作用;在我的例子中,一次性用品从不   实际上,我们希望尽快关闭连接   操作完成

嗯,我很确定这就是RxSwift的人会做的事情。
如果您得到了结果,无论是completed还是error,您都会处置观察者。如果你想再次这样做,那么你re-subscribe

您可以使用其中一个功能进行处理:

  • 使用take系列:take(1)takeUntil ...
  • 完成后,请在观察者上调用dispose()。 (劝阻)
  • 使用debug()查看观察员的处置时间
  • ...

答案 1 :(得分:1)

“使用RxSwift构造”有两种方法可以完成所需的工作。

Connection.establish(host)
    .flatMap { Observable.combineLatest(Observable.just($0), $0.sendData("foo")) }
    .flatMap { connection, _ in connection.close() }
    .subscribe(onNext: { /* all done */ })

或者如果您不介意插入地图,则可以:

Connection.establish(host)
    .flatMap { connection in
        connection.sendData("foo").map { (connection, $0) }
    }
    .flatMap { connection, _ in connection.close() }
    .subscribe(onNext: { /* all done */ })

请注意,combineLatestmap都从一开始就在库中。