SimpleFutures 0.2.0

SimpleFutures 0.2.0

测试已测试
Lang语言 SwiftSwift
许可证 MIT
发布上次发布2016年12月
SwiftSwift 版本3.0
SPM支持 SPM

Troy Stribling 维护。



SimpleFutures: Scala Futures for Swift

Scala Futures 的一个 Swift 实现,包含更多功能。

动机

在非阻塞式异步请求和串行化请求处理、错误恢复和过滤的连接接口上有 Futures 的界面。在大多数 iOS 库中,异步接口是通过代理协议模式实现,或在一些情况下使用回调。即使简单的实现也可能导致业务逻辑分散到多个文件或深度嵌套的回调,使得难以跟踪。将看到 Futures 悠然解决了这个问题。

SimpleFutures 是 Futures 在 Swift 上的一个实现,受 BrightFutures 的启发。

要求

  • iOS 9.0+
  • Xcode 8.1

安装

手动

  1. 将 SimpleFutures 放到您的项目目录中的某个地方。您可以将其复制或添加为一个 git submodule
  2. 打开 SimpleFutures 项目目录,并将 SimpleFutures.xcodeproj 拖到您应用程序的 Xcode 项目的项目导航器中。
  3. 在您的项目 信息 选项卡下,设置 iOS 部署目标 为 9.0,并确认 SimpleFutures.xcodeproj 的 iOS 部署目标 也是 9.0。
  4. 在您的项目目标的 通用 选项卡下,将顶部的 SimpleFutures.framework 添加为 嵌入的二进制文件
  5. 构建阶段 选项卡下,将 SimpleFutures.framework 添加为 目标依赖关系,并在 链接二进制与库 下添加。

另一个选项是将 SimpleFutures.swift 直接添加到您的项目中,因为整个库都包含在一个文件中。

队列

提供了一个简单的围绕 GCD 的包装。

// create a queue with .background pos
let queue = Queue("us.gnos.myqueue")

// run block synchronously on queue
queue.sync {
  // do something
}

// return a value from a synchronous task
let result = queue.sync {
  // do something
  return value
}

// run block asynchronously on queue
queue.async {
  // do something
}

// run block asynchronously at specified number of seconds from now
queue.delay(10.0) {
  // do something
}

执行上下文

执行上下文 执行任务,并通过协议的实现来定义它,

public protocol ExecutionContext {
    func execute(task: Void -> Void)
}

SimpleFutures 提供一个 QueueContext,它在指定的 Queue 上异步执行任务,以及一个 ImmediateContext,它在调用线程上同步执行任务。

// main and global queue contexts
QueueContext.main
QueueContext.global

// create a QueueContext using queue
public init(queue: Queue)

// immediate context runs tasks synchronously on the calling thread
ImmediateContext()

FuturesFutureStreams 的完成处理程序和组合器在指定的上下文中运行。默认上下文是 QueueContext.main

ImmediateContext() 对于测试可能很有用。

Future

Future 实例是对可以在未来的任何时候计算的不变结果的只读封装。当结果被计算时,称 Future 已完成。一个 Future 可以成功完成并返回一个值,或者因为错误而失败。

Future 还提供组合方法,允许多个实例一起链式调用并顺序执行,同时还提供了可以同时评估多个 Futures 的容器方法。

本节将讨论这些主题的每个细节。

创建

Future 可以使用 future 方法、一个 Promise 或初始化器进行创建。

init

init 方法可用于创建具有指定结果的未来。

// create an uncompleted future
public init()

// create a future with result of type T
public init(value: T)

// create a Future with an error result
public init(error: Swift.Error)

future

提供了几种版本的 future 以便于与现有代码集成。

最简单的版本接受一个同步的 @autoclosure 或闭包。

// task is executed synchronously
public func future<T>( _ task: @autoclosure @escaping (Void) -> T) -> Future<T>

// task is executed in context which may be asynchronous
public func future<T>(context: ExecutionContext = QueueContext.futuresDefault, _ task: @escaping (Void) throws -> T) -> Future<T>

还提供了接受异步闭包参数的版本,这些闭包参数遵循常见的完成块形式。

public func future<T>(method: (@escaping (T, Swift.Error?) -> Void) -> Void) -> Future<T>

public func future<T>(method: (@escaping (T, Swift.Error?) -> Void) -> Void) -> Future<T>

public func future<T>(method: (@escaping (T) -> Void) -> Void) -> Future<T>

使用 future 简单地向现有代码中添加 Future 接口。考虑以下类,它有一个异步请求,接受完成块:

class AsyncRequester {

    func request(completion: @escaping (Int?, Swift.Error?) -> Void)

}

为添加 Future 接口添加一个扩展将看起来像:

extension AsyncRequester {

    func futureRequest() -> Future<Int?> {
        return future(method: request)
    }

}

Promise

Promise 实例是 一次性可写的,并包含一个 Future。当 成功完成Future 时,Promise 将值写入 Future 结果,当 失败完成 时将错误写入其 Future 结果。

// Create and uncompleted Promise
public init()

// Completed Promise with another Future
public func completeWith(context: ExecutionContext = QueueContext.futuresDefault, future: Future<T>)

// Complete Promise successfully with value
public func success(_ value: T)

// Complete Promise with error
public func failure(_ error: Swift.Error)

Future 接口实现可以使用 Promise 来创建和管理 Future

下面是一个简单的 URLSession extension,它添加了一个执行 HTTP GET 请求并返回 Future 的方法。

extension URLSession {

    class func get(with url: URL) -> Future<(Data?, URLResponse?)> {
        let promise = Promise<(Data?, URLResponse?)>()
        let session = URLSession.shared
        let task = session.dataTask(with: url) { (data, response, error) in
            if let error = error {
                promise.failure(error)
            } else {
                promise.success((data, response))
            }
        }
        task.resume()
        return promise.future
    }

}

在应用程序中使用:

let requestFuture = URLSession.get(with: URL(string: "http://troystribling.com")!)

处理完成

设置 Future 结果的值 完成 它。持有 Future 参考的实体通过方法 onSuccessonFailure 通知 完成。上一节中的 requestFuture 会使用以下方法处理 完成 事件:

requestFuture.onSuccess { (data, response) in
    guard let response = response, let data = data else {
        return
    }
    // process data
}

requestFuture.onFailure { error in
    // handle error
}

可以为单个 Future 定义多个完成处理程序。

完成 With

Future 可以使用 completeWith 使用另一个 Future 的结果来完成。

public func completeWith(context: ExecutionContext = QueueContext.futuresDefault, future: Future<T>)

例如:

let anotherFuture = Future<Int>()
func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)

let dependentFuture = future(method: asyncRequest)
anotherFuture.completeWith(future: dependentFuture)

组合器

组合器是用于构建一个序列化的 Future 链(执行异步请求并应用映射和过滤请求结果)的方法。

map

mapping: (T) throws -> M 应用到成功的 Future<T> 结果,以产生一个不同类型的 Future<M>

public func map<M>(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), mapping: @escaping (T) throws -> M) -> Future<M>

例如:

enum AppError: Error {
    case invalidValue
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)

let mappedFuture = future(method: asyncRequest).map { value -> String in
    guard value < 0 else {
        throw AppError.invalidValue
    }
    return "\(value)"
}

flatMap

将一个mapping: (T) throws -> Future应用到成功的Future返回的Future上。使用flatMap来串行异步请求。

public func flatMap<M>(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), mapping: @escaping (T) throws -> Future<M>) -> Future<M>

例如:

enum AppError: Error {
    case invalidValue
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func asyncMapping(Int) -> Future<String>

let mappedFuture = future(method: asyncRequest).flatMap { value -> Future<String> in
    guard value < 0 else {
        throw AppError.invalidValue
    }
    return asyncMapping(value)
}

flatMap通常需要指定闭包的返回类型。它是一个重载方法,编译器有时需要帮助来确定使用哪个。

withFilter

将一个filter: (T) throws -> Bool应用到成功的Future上,如果filter过滤成功,则返回Future,如果filter失败,则抛出FuturesError.noSuchElement

public func withFilter(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), filter: @escaping (T) throws -> Bool) -> Future<T>

例如:

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)

let filteredFuture = future(method: asyncRequest).withFilter { value in
    value > 0
}

forEach

将一个映射apply: (T) -> Void应用到成功的Future上。这等价于使用完成处理器onSuccess

public func forEach(context:ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), apply: @escaping (T) -> Void)

例如:

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func apply(Int) -> Void

let forEachFuture = future(method: asyncRequest).forEach { value in
    apply(value)
}

andThen

将一个映射apply: (T) -> Void应用到成功的Future上,并返回一个原生的future完成后的结果Future。这等价于一个透传。在这里可以在组合链中处理数据,但不会影响Futureresult

public func andThen(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), completion: @escaping (T) -> Void) -> Future<T>

例如:

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func apply(Int) -> Void

let andThenFuture = future(method: asyncRequest).andThen { value in
    apply(value)
}

recover

将一个恢复映射recovery: (Swift.Error) throws -> T应用到失败的Future并返回一个Future

public func recover(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), recovery: @escaping (Swift.Error) throws -> T) -> Future<T>

例如:

enum AppError: Error {
    case invalidValue
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func recovery(Swift.Error) -> Int

let recoveryFuture = future(method: asyncRequest).recover { error in
    guard let appError = error as? AppError else {
        throw error
    }
    return recovery(appError)
}

recoverWith

将一个恢复映射recovery: (Swift.Error) throws -> Future应用到失败的Future并返回一个Future

public func recoverWith(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), recovery: @escaping (Swift.Error) throws -> Future<T>) -> Future<T>

例如:

enum AppError: Error {
    case invalidValue
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func recovery(Swift.Error) -> Future<Int>

let recoveryFuture = future(method: asyncRequest).recoverWith { error -> Future<Int> in
    guard let appError = error as? AppError else {
        throw error
    }
    return recovery(appError)
}

recoverWith通常需要指定闭包的返回类型。它是一个重载方法,编译器有时需要帮助来确定使用哪个。

mapError

将一个映射mapping: (Swift.Error) -> Swift.Error应用到失败的Future并返回一个带有新错误结果的Future

public func mapError(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), mapping: @escaping (Swift.Error) -> Swift.Error) -> Future<T>

例如,将任何Swift.Error转换为AppError,

enum AppError: Error {
    case invalidValue
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func mapping(Swift.Error) -> AppError.Error

let mapErrorFuture = future(method: asyncRequest).mapError { error in
    guard let appError = error as? AppError else {
        return mapping(error)
    }
   return appError
}

fold

将一个mapping: (R, Iterator.Element.T) throws -> R应用到数组[Future]上,将结果累积到新的Future中。如果任何一个Future失败,则Future也会失败。

 public func fold<R>(context: ExecutionContext = QueueContext.futuresDefault, initial: R,  combine: @escaping (R, Iterator.Element.T) throws -> R) -> Future<R> 

例如:

fun asyncTask(Int) -> Future<Int>

let futures = [asyncTask(1), asyncTask(1), asyncTask(1)] 

let foldFuture = futures.fold(initial: 0) { $0 + $1 } 

sequence

[Future]转换为在[Future}完成时完成数组所有结果的Future<[T]>。使用sequence来累积无关异步请求的结果。

public func sequence(context: ExecutionContext = QueueContext.futuresDefault) -> Future<[Iterator.Element.T]>

例如:

fun asyncTask(Int) -> Future<Int>

let futures = [asyncTask(1), asyncTask(1), asyncTask(1)] 

let sequenceFuture = futures.sequence() 

cancel

一个Future可以在应用程序中传递来通知不同组件的事件。可以指定多个完成处理器定义和组合链。并非所有的应用程序组件都会对这个事件感兴趣,可能想”退订“。

应用程序可以使用CancelToken()取消多个完成处理器回调和组合执行。

fun asyncRequest() -> Int
fun anotherAsyncRequest() -> Future<String>

let cancelToken = CancelToken()
let cancelFuture = future(method: asyncRequest)

let mappedFuture = cancelFuture.flatMap(cancelToken: cancelToken) {
    anotherAsyncRequest()
}

mappedFuture.onSuccess(cancelToken: cancelToken) { value in
    // process data
}

mappedFuture.onFailure(cancelToken: cancelToken) { ==error in
    // process data
}

cancelFuture.cancel(cancelToken)

FutureStream

在诸如CoreLocation之类的框架中,CLLocationManager的单个实例可能会反复调用CLLocationManagerDelegate方法。

func locationManager(_ manager: CLLocationManager!,
           didUpdateLocations locations: [AnyObject]!)

由于Futures是不可变的,每次调用都必须创建一个新的实例。FutureStreams是只读的完成Future容器,可以用于在这种情况下以指定的容量持久保存所有过去的调用。FutureStreams支持类似于Futures的接口,可以使用组合子与它们一起使用。

创建

可以使用futureStream方法、StreamPromise或初始化器创建FutureStream

init

init 方法可用于创建具有指定结果的未来。

// create an empty FutureStream with capacity
public init(capacity: Int)

// create a FutureStream with an Int result and capacity of 10
public init(value: T, capacity: Int)

// create a FutureStream with an error result and capacity of 10
public init(error: Swift.Error, capacity: Int)

futureStream

提供了几个版本的futureStream,以简化与现有代码的集成。

最简单的一种接受一个同步闭包并在指定的上下文中执行它。

public func futureStream<T>(context: ExecutionContext = QueueContext.futuresDefault, _ task: @escaping (Void) throws -> T) -> FutureStream<T>

还提供了接受常见完成块闭包参数的版本。

public func futureStream<T>(method: (@escaping (T, Swift.Error?) -> Void) -> Void) -> FutureStream<T> 

public func futureStream(method: (@escaping (Swift.Error?) -> Void) -> Void) -> FutureStream<Void>

public func futureStream<T>(method: (@escaping (T) -> Void) -> Void) -> FutureStream<T>

使用futureStream,向现有代码添加FutureStream接口很简单。考虑以下一个带有完成块异步请求的类,

class TestStreamRequester {

    func request(completion: @escaping (Int?, Swift.Error?) -> Void)}

}

extension TestStreamRequester {

    func streamRequest() -> FutureStream<Int?> {
        return futureStream(method: request)
    }

}

StreamPromise

类似于PromiseStreamPromise只写的。它创建并完成 Futures并将它们添加到FutureStream中。

// Create and uncompleted StreamPromise with capacity
public init(capacity: Int = Int.max)

// Complete StreamPromise with another Future
public func completeWith(context: ExecutionContext = QueueContext.futuresDefault, future: Future<T>)

// Complete StreamPromise with another FutureStream
public func completeWith(context: ExecutionContext = QueueContext.futuresDefault, stream: FutureStream<T>)

// Complete StreamPromise successfully with value
public func success(_ value: T)

// Complete StreamPromise with error
public func failure(_ error: Swift.Error)

FutureStream接口实现可以使用StreamPromise创建FutureStream

在此,一个简单的Accelerometer服务实现被展示,通过FutureStream提供加速度计数据更新。

import UIKit
import CoreMotion
import BlueCapKit

class Accelerometer {

    var motionManager = CMMotionManager()
    let queue = OperationQueue.main
    let accelerationDataPromise = StreamPromise<CMAcceleration>(capacity: 10)

    var updatePeriod: TimeInterval {
        get {
            return motionManager.accelerometerUpdateInterval
        }
        set {
            motionManager.accelerometerUpdateInterval = newValue
        }
    }

    var accelerometerActive: Bool {
        return motionManager.isAccelerometerActive
    }

    var accelerometerAvailable: Bool {
        return motionManager.isAccelerometerAvailable
    }

    init() {
        motionManager.accelerometerUpdateInterval = 1.0
    }

    func startAcceleromterUpdates() -> FutureStream<CMAcceleration> {
        motionManager.startAccelerometerUpdates(to: queue) { [unowned self] (data: CMAccelerometerData?, error: Error?) in
            if let error = error {
                self.accelerationDataPromise.failure(error)
            } else {
                if let data = data {
                    self.accelerationDataPromise.success(data.acceleration)
                }
            }
        }
        return accelerationDataPromise.stream
    }

    func stopAccelerometerUpdates() {
        motionManager.stopAccelerometerUpdates()
    }
}

在应用程序中使用:

let accelerometer = Accelerometer()

let accelrometerDataFuture = accelerometer.startAcceleromterUpdates()

处理完成

FutureStream添加一个完成 Future将调用其完成处理程序。当通过onSuccessonFailure方法向FutureStream添加一个完成 Future时,保持FutureStream引用的对象将被通知。前一节中的accelerometerDataFuture将通过以下方式处理完成事件:

accelrometerDataFuture.onSuccess { data in
   // process data
}
accelrometerDataFuture.onFailure { error in
  // handle error
}

可以为单个FutureStream定义多个完成处理程序。

completeWith

可以使用completeWith使用另一个FutureFutureStream的结果完成一个FutureStream

func completeWith(context: ExecutionContext = QueueContext.futuresDefault, stream: FutureStream<T>)

func completeWith(context: ExecutionContext = QueueContext.futuresDefault, future: Future<T>)

例如:

let anotherFutureStream = FutureStream<Int>()
func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)

// Complete FutureStream with dependent Future
let dependentFuture = future(method: asyncRequest)
anotherFutureStream.completeWith(future: dependentFuture)

// Complete FutureStream with dependent FutureStream
let dependentStream = futureStream(method: asyncRequest)
anotherFutureStream.completeWith(future: dependentStream)

组合子

组合子是用于构造一个序列化链的FutureStreams的方法,该链执行异步请求并应用映射和过滤。

map

mapping: (T) throws -> M应用到成功的FutureStream<T>的结果,以产生一个不同类型的FutureStream<M>

public func map<M>(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), mapping: @escaping (T) throws -> M) -> FutureStream<M>

例如:

enum AppError: Error {
    case invalidValue
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)

let mappedStream = futureStream(method: asyncRequest).map { value -> String in
    guard value < 0 else {
        throw AppError.invalidValue
    }
    return "\(value)"
}

mapping将在相关的依赖于的FutureStream成功完成时被调用。

flatMap

对成功的FutureStream<T>的结果应用futureMapping: (T) throws -> Future<M>streamMapping: (T) throws -> FutureStream<M>返回FutureStream<M>。使用flatMap对异步请求和流进行序列化。

// Apply a mapping returning a FutureStream to a FutureStream result
public func flatMap<M>(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), mapping: @escaping (T) throws -> FutureStream<M>) -> FutureStream<M>

// Apply a mapping returning a Future to a FutureStream result
public func flatMap<M>(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), mapping: @escaping (T) throws  -> Future<M>) -> FutureStream<M>

例如:

enum AppError: Error {
    case invalidValue
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func streamMapping(Int) -> FutureStream<String>

let mappedStream = futureStream(method: asyncRequest).flatMap { value -> FutureStream<String> in
    guard value < 0 else {
        throw AppError.invalidValue
    }
    return streamMapping(value)
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func futureMapping(Int) -> Future<String>

let mappedStream = futureStream(method: asyncRequest).flatMap { value -> Future<String> in
    guard value < 0 else {
        throw AppError.invalidValue
    }
    return futureMapping(value)
}

可以将映射 streamMapping: (T) throws -> FutureStream<M> 应用到成功的 Future<T> 的结果中,从而返回一个 FutureStream<M>

// Apply a mapping to Future returning a FutureStream
public func flatMap<M>(capacity: Int = Int.max, context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), mapping: @escaping (T) throws -> FutureStream<M>) -> FutureStream<M>   

例如:

let mappedStream = futureStream(method: asyncRequest).flatMap { value -> FutureStream<String> in
    guard value < 0 else {
        throw AppError.invalidValue
    }
    return streamMapping(value)
}

flatMap通常需要指定闭包的返回类型。它是一个重载方法,编译器有时需要帮助来确定使用哪个。

withFilter

filter: (T) throws -> Bool 应用到成功的 FutureStream<T> 的结果中。如果过滤器成功,则返回 FutureStream<T>,如果过滤器失败,则抛出 FuturesError.noSuchElement

public func withFilter(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), filter: @escaping (T) throws  -> Bool) -> FutureStream<T>

例如:

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)

let filteredStream = futureStream(method: asyncRequest).withFilter { value in
    value > 0
}

forEach

将映射 apply: (T) -> Void 应用到一个成功的 FutureStream<T>。这相当于使用 onSuccess 完成处理程序。

public func forEach(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), apply: @escaping (T) -> Void)

例如:

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func apply(Int) -> Void

let forEachStream = futureStream(method: asyncRequest).forEach { value in
    apply(value)
}

andThen

将映射 apply: (T) -> Void 应用到成功的 FutureStream<T> 并返回一个用原始流的结果完成的 FutureStream<T>。这相当于转发。在这里可以处理数据组合链,但不会影响 FutureStream<T> 的结果。

public func andThen(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), completion: @escaping (T) -> Void) -> FutureStream<T>

例如:

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func apply(Int) -> Void

let andThenStream = futureStream(method: asyncRequest).andThen { value in
    apply(value)
}

recover

将对 FutureStream<T> 失败应用恢复映射 recovery: (Swift.Error) throws -> T 返回 FutureStream<T>

public func recover(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), recovery: @escaping (Swift.Error) throws -> T) -> FutureStream<T>

例如:

enum AppError: Error {
    case invalidValue
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func recovery(Swift.Error) -> Int

let recoveryStream = futureStream(method: asyncRequest).recover { error in
    guard let appError = error as? AppError else {
        throw error
    }
    return recovery(appError)
}

recoverWith

将对 FutureStream<T> 失败应用恢复映射 futureRecovery: (Swift.Error) throws -> Future<T>streamRecovery: (Swift.Error) throws -> FutureStream<T> 返回一个 FutureStream。

// Apply a recovery returning a FutureStream to a FutureStream result
 public func recoverWith(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), recovery: @escaping (Swift.Error) throws -> FutureStream<T>) -> FutureStream<T>

// Apply a recovery returning a Future to a FutureStream result
public func flatMap<M>(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), mapping: @escaping (T) throws  -> Future<M>) -> FutureStream<M>

例如:

enum AppError: Error {
    case invalidValue
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func streamRecovery(Swift.Error) -> FutureStream<Int>

let recoveryStream = futureStream(method: asyncRequest).recoverWith { error -> FutureStream<Int> in
    guard let appError = error as? AppError else {
        throw error
    }
    return streamRecovery(appError)
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func futureRecovery(Swift.Error) -> Future<Int>

let recoveryStream = futureStream(method: asyncRequest).recoverWith { value -> Future<String> in
    guard value < 0 else {
        throw AppError.invalidValue
    }
    return futureRecovery(value)
}

streamRecovery: (Swift.Error) throws -> FutureStream<T> 也可以应用于失败的 Future<T>,返回一个 FutureStream<M>

public func recoverWith(capacity: Int = Int.max, context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), recovery: @escaping (Swift.Error) throws -> FutureStream<T>) -> FutureStream<T>

例如:

let recoveryStream = futureStream(method: asyncRequest).recoverWith { error -> FutureStream<Int> in
    guard let appError = error as? AppError else {
        throw error
    }
    return streamRecovery(appError)
}

recoverWith通常需要指定闭包的返回类型。它是一个重载方法,编译器有时需要帮助来确定使用哪个。

mapError

将对 FutureStream<T> 失败应用映射 mapping: (Swift.Error) -> Swift.Error 并返回一个具有映射错误结果的 FutureStream<T>

public func mapError(context: ExecutionContext = QueueContext.futuresDefault, cancelToken: CancelToken = CancelToken(), mapping: @escaping (Swift.Error) -> Swift.Error) -> FutureStream<T>

例如,将任何Swift.Error转换为AppError,

enum AppError: Error {
    case invalidValue
}

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
func mapping(Swift.Error) -> AppError

let mapErrorStream = futureStream(method: asyncRequest).mapError { error in
    guard let appError = error as? AppError else {
          return mapping(error)
    }
    return appError
}

cancel

可以将 FutureStream 在应用程序中传递,以通知不同的组件事件。可以指定多个完成处理程序定义和组合链。并非所有应用程序组件都对事件感兴趣,并且可能想要'退订'。

应用程序可以使用CancelToken()取消多个完成处理器回调和组合执行。

func asyncRequest(_ completion: @escaping (Int, Swift.Error?) -> Void)
fun asyncStream() -> FutureStream<String>

let cancelToken = CancelToken()
let cancelStream = futureStream(method: asyncRequest)

let mappedStream = cancelStream.flatMap(cancelToken: cancelToken) {
    asyncStream()
}

mappedStream.onSuccess(cancelToken: cancelToken) { value in
    // process data
}

mappedStream.onFailure(cancelToken: cancelToken) { ==error in
    // process data
}

cancelFuture.cancel(cancelToken)

测试用例

测试用例可提供。要构建 workspace

pod install

并在生成的 workspacetest 选项卡中运行。

项目

以下项目使用 SimpleFutures。它们可以用作实际应用使用的指南。

  1. BlueCap 提供了一个基于 Futures 的 CoreBluetooth 替换。
  2. FutureLocation 提供了一个基于 Futures 的 CoreLocation 替换。