未来就在眼前– iOS和异步开发

在编程中,我们经常使用异步操作。 这可能包括诸如网络,文件系统,数据库,UI,长时间运行的任务或任何其他I / O事件之类的东西。 在iOS中,我们有许多机制可以处理此问题,包括GCD,NSOperation,NSNotifications,委托和回调。

期货是一种在iOS上不那么常见的结构,但已经很成熟,在其他语言(例如JavaScript和Scala)中更常见。 也称为诺言,延期,任务或异步; 该技术允许您以同步方式处理异步值,将连续传递样式的调用切换为直接样式。 通过使用期货,您的程序将更容易推理,因为不会有太多的嵌套调用。

但是未来到底是什么? 未来是对尚不可用的值的表示。 当您与未来合作时,您将不知道该值当前是否可用。 但是,您可以使用该值,就好像它可用一样。 价值一经获得,将来便会处理您的指示。

期货框架

如果您想在iOS应用中开始使用期货,则可以选择以下两种不同的第三方库:

BrightFutures

PromiseKit

FutureKit

递延

螺栓

根据您选择的库,您将有不同的设计选择可以使用。 例如,Big Nerd Ranch的Deferred库的灵感来自OCaml的Deferreds。 这意味着将来/延迟值不会说明异步操作是否失败。 要表示失败,您需要通过返回Result类型或类似的关联枚举来将其表示为值的一部分。 BrightFutures遵循Scala的承诺和未来,因此有一个隐含的理解,即每个未来都可能失败。 FutureKit和Bolts还包含“已取消”状态,该状态表示用户何时取消了将来/任务并且不再关心结果。

这些库可能具有不同的方法和设计目标。 但是,它们都解决了提供一个接口来表示异步结果并使用异步结果的相同问题。 它们还处理共同的任务,例如一起对期货进行排序,并行运行期货以及在特定线程上处理结果。

因此,让我们深入。

只是基础

使用期货的最基本方法是设置完成处理程序。 只要值可用,就可以简单地执行操作。 要设置处理程序,您可以在将来通过调用onSuccess (BrightFutures / FutureKit), (Deferred), 然后 (PromiseKit)或continueOnSuccessWith (Bolts)来设置延续功能。 这些框架中的大多数还允许您通过调用onFailure (BrightFutures), onError (FutureKit)或catch (PromiseKit)来附加错误处理程序。

这应该类似于仅使用回调来处理异步任务。 这里的主要区别是您仍然会有一个userFuture 之后可以对其进行进一步处理的对象,例如通过添加更多的完成处理程序或传递给另一个函数或组件。

期货映射

使用期货时,我们可以传递未来,而无需使用回调处理价值。 假设我们有一种类型的未来(例如Future ),但是我们需要另一种类型的未来(例如Future <User >)。 如果我们有一个可以将第一个内部类型(JSON)转换为第二个内部类型( User )的函数,则可以在Future 上调用map并传入映射函数以获取Future 。

排序期货

在处理多个期货时,有时您需要一个期货的结果才能获得另一个期货。 例如,如果您需要在获取用户地址之前查找用户,则可能需要像下面这样连接两个请求:

尽管这是有效的,但请注意您的主要逻辑将如何嵌套在两个完成模块中。 另请注意,如果对getUser的调用失败,我们将无法运行getAddress。 链接期货或对期货进行排序的操作非常普遍,您可以调用期货上的一个函数来执行此操作。 该函数的名称为flatMap (BrightFutures / Deferred), 然后命名为(PromiseKit), continueWithTask (Bolts)或onSuccess (FutureKit)。

平行期货

另一种常见的情况是,当您拥有多个彼此不依赖的期货,并且在继续操作之前需要所有值。 大多数未来框架将具有将一组期货转换成一个包含一组值的单一期货的功能。 如果所有期货均成功,则新的期货将返回一个包含所有期货值的数组。 此函数称为序列 (BrightFutures), Task.whenAll (Bolts), joinedValues (Deferred)或when (PromiseKit)。

多个异步值

尽管前景很好,但它们并不适合每种异步处理。 例如,如果您想构建一个聊天应用,则需要处理来自其他用户的无数消息。 在这种情况下,需要一个反应性结构(例如Signal,ObservableStream )。 这些类似于期货,不同之处在于它们提供了一系列值而不是一个值。 期货实际上可以被视为一种特殊的信号,它仅返回一个值。 有关此的更多信息,请查看RxSwift或ReactiveCocoa框架。

句法糖

需要注意的另一件事是,通过为Swift编程语言提供其他关键字,我们可以使我们的代码看起来更像同步编程,同时保留异步编程的优点。 C#和JavaScript使用async / await关键字完成了此任务。 这就是Swift中的样子:

resolveAge实际上将返回Future ,而retrieveUserFromDB将返回Future 。 通过使用await关键字,其余代码将变为异步状态,并将等待直到retrieveAge返回,从而将其余代码有效地放入onSuccess处理程序中,如下所示:

请注意,使用await如何隐藏使用期货的事实,并使代码看起来像同步命令式编程,这对许多人来说应该很熟悉。

从Swift 3开始,Swift尚不存在此功能。 但是,根据迅速发展邮件列表上的消息,克里斯·拉特纳说这可能是Swift 4 Stage 2的一项尝试。 因此,希望我们最终能看到这一点。

结论

如果您需要处理异步结果,则期货是一个很好的构造。 与简单的回调相比,它们具有许多优点,因为您可以传递它们并将它们按顺序或并行组合在一起。 现在,您必须使用第三方框架来获得此功能,但是现在要了解期货,以便在编程库中使用该工具。 这样,您将准备好将期货完全集成到Swift编程语言中。