EasyFutures 1.2.0

EasyFutures 1.2.0

Dima Mishchenko 维护。



  • 作者
  • Dima Mishchenko

EasyFutures

Swift 4.2 CocoaPods compatible Build Status codecov.io Packagist

Swift 实现 Futures & Promises。您可以在维基百科上了解更多关于 Futures & Promises 的信息:https://en.wikipedia.org/wiki/Futures_and_promises

EasyFutures

文档

  • 完整的文档和更多示例您可以在 Playground 中找到(为了使用 playground,您应该在 EasyFutures.xcodeproj 中打开它并构建 EasyFutures 框架)。
  • Wiki(完整的文档和所有示例)。
  • 单元测试.
  • 示例部分.

需求

  • iOS 9.0+

安装

CocoaPods

  • 将以下行添加到您的 Podfile
pod 'EasyFutures'
  • 在您的 Podfile 中添加 use_frameworks!
  • 运行 pod install
  • 添加到文件
import EasyFutures

示例

传统编写异步代码的方式

func loadChatRoom(_ completion: (_ chat: Chat?, _ error: Error?) -> Void) {}
func loadUser(id: String, _ completion: (_ user: User?, _ error: Error?) -> Void) {}

loadChatRoom { chat, error in
    if let chat = chat {
        loadUser(id: chat.ownerId) { user, error in
            if let user = user {
                print(user)
                // owner loaded
            } else {
                // handle error
            }
        }
    } else {
        // handle error
    }
}

带有 EasyFutures 的相同逻辑

func loadChatRoom() -> Future<Chat>
func loadUser(id: String) -> Future<User> 

loadChatRoom().flatMap({ chat -> Future<User> in
    // loading user
    return loadUser(id: chat.ownerId)
}).onSuccess { user in
    // user loaded
}.onError { error in
    // handle error
}

Future

Future 是一个包含或将要包含 result 的对象,该 result 可以是值或错误。通常结果来自某些异步过程。为了接收结果,您可以定义 onCompleteonSuccessonError 回调。

func loadData() -> Future<String> 

let future = loadData()

future.onComplete { result in
    switch result {
    case .value(let value):
        // value
    case .error(let error):
        // error
    }
}

future.onSuccess { data in
    // value
}.onError { error in
    // error
}

Promise

Promise 用于编写返回 Future 的函数。Promise 包含 Future 实例并可以完成它。

func loadData() -> Future<String> {

    // create the promise with String type
    let promise = Promise<String>()

    // check is url valid
    guard let url = URL(string: "https://api.github.com/emojis") else {
        // handle error
        promise.error(ExampleError.invalidUrl)
        return promise.future
    }

    // loading data from url
    let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
        if let data = data, let string = String(data: data, encoding: .utf8) {
            // return result
            promise.success(string)
        } else {
            // handle error
            promise.error(ExampleError.cantLoadData)
        }
    }
    task.resume()

    // return the future
    return promise.future
}

loadData().onSuccess { data in
    DispatchQueue.main.async {
        self.label.text = data
    }
}.onError { error in
    print(error)
    // handle error
}

Composition

地图

返回新的Future,如果闭包中返回的结果成功,则包含该结果;如果第一个Future包含错误,则包含错误。

let future = Future<Int>(value: 100)
future.onSuccess { value in
    // value == 100
}

let mapFuture = future.map { value -> String in
    return "\(value) now it's string"
}
mapFuture.onComplete { result in
    switch result {
    case .value(let value):
        print(value) // "100 now it's string""
    case .error(let error):
        // handle error
    }
}

flatMap

返回新的Future,如果闭包中返回的Future存在,则包含该Future;如果第一个Future包含错误,则包含错误。

let future = Future<Int>(value: 1)

let flatMapFuture = future.flatMap { value -> Future<String> in
    return Future<String>(value: "\(value * 100)%")
}
flatMapFuture.onSuccess { value in
    print(value) // "100%"
}

filter

如果值满足过滤条件,则返回Future;否则返回错误。

let future = Future<Int>(value: 500)

future.filter { value -> Bool in
    return value > 100
}.onComplete { result in
    switch result {
    case .value(let value):
        print(value) // 100
    case .error(let error):
        print(error) // no error
    }
}

future.filter { value -> Bool in
    return value > 1000
}.onComplete { result in
    switch result {
    case .value(let value):
        print(value) // no value
    case .error(let error):
        print(error) // FutureError.filterError
    }
}

recover

如果Future包含错误或将要包含错误,你可以使用新值来恢复。

let future = Future<Int>(error: someError)

future.recover { error -> Int in
    return 100
}.onComplete { result in
    switch result {
    case .value(let value):
        print(value) // 100
    case .error(let error):
        print(error) // no error
    }
}

zip

将两个值组合成一个元组。

let first = Future<Int>(value: 1)
let second = Future<Int>(value: 2)

first.zip(second).onSuccess { firstValue, secondValue in
    print(firstValue) // 1
    print(secondValue) // 2
}

andThen

返回新的Future,其中包含相同的值。

let future = Future<String>(value: "and")

future.andThen { value in
    print(value) // "and"
}.andThen { value in
    print(value.count) // 3
}

flatten

如果Future的值是另一个Future,您可以将其扁平化。

let future = Future<Future<String>>(value: Future<String>(value: "value"))

future.onSuccess { value in
    print(value) // Future<String>(value: "value")
}

future.flatten().onSuccess { value in
    print(value) // "value"
}

处理错误

mapflatMapfilterrecover 可以捕获错误,并返回带有该错误的消息的Future,因此您无需使用 do/catch 来处理它。

let future = Future<String>(value: "")
let errorToThrow = NSError(domain: "", code: -1, userInfo: nil)

future.map { value -> String in
    throw errorToThrow
}.flatMap { value -> Future<String> in
    throw errorToThrow
}.filter { value -> Bool in
    throw errorToThrow
}.recover { error -> String in
    throw errorToThrow
}

序列

EasyFutures 提供了一些函数来帮助您处理Future的序列。

折叠(fold)

您可以将一系列值转换为单个值。折叠返回一个包含此值的Future。折叠接受默认值,然后您使用默认值与列表中的每个值进行操作。可以捕获错误。

let futures = [Future<Int>(value: 1), Future<Int>(value: 2), Future<Int>(value: 3)]

futures.fold(0) { defaultValue, currentValue -> Int in
    return defaultValue + currentValue
}.onSuccess { value in
    print(value) // 6
}

遍历(traverse)

遍历可以与任何序列一起工作。接受一个闭包,将值转换为Future。返回一个包含从闭包返回的Future值数组的Future。

[1, 2, 3].traverse { number -> Future<String> in
    return Future<String>(value: "\(number * 100)")
}.onSuccess { value in
    print(value) // ["100", "200", "300"]
}

序列(sequence)

将一系列Future转换为包含值的单个Future。

let futures = [Future<Int>(value: 1), Future<Int>(value: 2), Future<Int>(value: 3)] // [Future<Int>, Future<Int>, Future<Int>]
let sequence = futures.sequence() // Future<[Int]>
sequence.onSuccess { numbers in
    print(numbers) // [1, 2, 3]
}

许可证

EasyFutures 适用于 MIT 许可证。有关更多信息,请参阅 LICENSE 文件。