SwiftAsync 0.2.0

SwiftAsync 0.2.0

测试已测试
Lang语言 SwiftSwift
许可证 MIT
发布最后一个发布2016年3月
SPM支持 SPM

赖志炫 维护。



Async

Swift 的异步/等待控制流。

异步/等待将这个:

// example credit to: http://promisekit.org/chaining
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    let md5 = md5ForData(data)
    dispatch_async(dispatch_get_main_queue()) {
        self.label.text = md5
        UIView.animateWithDuration(0.3, animations: {
            self.label.alpha = 1
            }) {
            // this is the end point
            // add code to happen next here
        }
    }
}

变成这个:

async {
    let md5 = md5ForData(data)
    await { async(.Main) { self.label.text = md5 } }
    await { UIView.animateWithDurationAsync(0.3) {self.label.alpha = 1} }
    // this is the end point
    // add code to happen next here
}() {}

安装

Async 通过 CocoaPods 提供。要安装它,只需将以下行添加到您的 Podfile 中

pod "SwiftAsync"

用法

示例项目和 测试文件 将帮助您入门。

要运行示例项目,首先克隆仓库,然后从 Example 目录中运行 pod install

先决条件

异步

以下是创建异步函数的方式

let createImage = async {() -> UIImage in
    sleep(3)
    return UIImage()
}

以下是使用回调调用异步函数的方式

createImage() {image in
  // do something with the image
}

以下是创建具有参数的异步函数的方式

let fetchImage = {(URL: NSURL) in
    async {() -> UIImage in
        // fetch the image synchronously
        let image = get(URL)
        return image
    }
}

fetchImage(URL)() {image in
    // do something with the image
}

让我们定义更多的异步函数

let processImage = {(image: UIImage) in
    async {() -> UIImage in
        sleep(1)
        return image
    }
}

let updateImageView = {(image: UIImage) in
    async(.Main) {
        self.imageView.image = image
    }
}

与调用回调链式调用异步函数不同,使用 await

print("creating image")
createImage {image in
    print("processing image")
    processImage(image)() {image in
        print("updating imageView")
        updateImageView(image)() {
            print("updated imageView")
        }
    }
}

async {
    print("creating image")
    var image = await { createImage }
    print("processing image")
    image = await { processImage(image) }
    print("updating imageView")
    await { updateImageView(image) }
    print("updated imageView")
}() {}

await

await 是一个阻塞/同步函数。因此,它决不应该在主线程中调用。它执行一个异步函数,该函数是类型为 (T -> Void) -> Void 的闭包,并以同步方式返回结果。

async {
    // blocks the thread until callback is called
    let message = await {(callback: (String -> Void)) in
        sleep(1)
        callback("Hello")
    }
    print(message) // "Hello"
}() {}

// equivalent to
async {
    let message = await {
        async {() -> String in sleep(1); return "Hello" }
    }
    print(message) // "Hello"
}() {}

// equivalent to
async {
    sleep(1)
    let message = "Hello"
    print(message) // "Hello"
} {}

以下是使用 await 包装异步 API(例如网络请求、动画等)并将它们同步化的方式

let session = NSURLSession(configuration: .ephemeralSessionConfiguration())

let get = {(URL: NSURL) in
    async { () -> (NSData?, NSURLResponse?, NSError?) in
        await {callback in session.dataTaskWithURL(URL, completionHandler: callback).resume()}
    }
}

// with unwrapping
let get2 = {(URL: NSURL) in
    async { () -> (NSData, NSURLResponse)? in
        let (data, response, error) = await {callback in session.dataTaskWithURL(URL, completionHandler: callback).resume()}
        guard let d = data, r = response where error != nil else { return nil }
        return (d, r)
    }
}

async {
  if let (data, response) = await {get2(NSURL())} {
    // do something
  }
}() {}

thunkify

或者,您还可以使用 thunkify,它将具有尾随闭包的函数转换为异步函数

extension UIView {
    class func animateWithDurationAsync(duration: NSTimeInterval, animations: () -> Void) -> (Bool -> Void) -> Void {
        return thunkify(.Main, function: UIView.animateWithDuration)(duration, animations)
    }
}

async {
  await { UIView.animateWithDurationAsync(0.3) {self.label.alpha = 1} }
}() {}

串行与并行

要按顺序运行异步函数,我们可以使用 for/while 循环,因为 await 是阻塞/同步的。

let URLs = [NSURL]()
async {
    var results = [NSData]()
    for URL in URLs {
        results.append(await { get(URL) })
    }
    print("fetched \(results.count) items in series")
}() {}

要并行运行异步函数,将与数组或字典中的异步函数一起调用 await

let URLs = [NSURL]()
async {
    let results = await(parallel: URLs.map(get))
    print("fetched \(results.count) items in parallel")
}() {}

其他 API

默认情况下,异步函数在具有 全局并发队列服务质量 QOS_CLASS_USER_INITIATED 上进行调度。要在不同的队列上调度

let taskOnMainThread = async(.Main) {
    // do something
}

let customQueue = dispatch_queue_create("CustomQueueLabel", DISPATCH_QUEUE_CONCURRENT)
let taskOnCustomQueue = async(.Custom(customQueue)) {
    // do something
}

默认情况下,await 会无限期等待异步函数完成。要添加超时

async {
    await(timeout: 0.4) { async { () -> Bool in NSThread.sleepForTimeInterval(0.3); return true } }
}() {value in}

错误处理

async$await$asyncawait 使用相同的 API。此外,它们处理抛出的错误

enum Error: ErrorType {
    case TestError
}

let willThrow = async$ {() throws in
    NSThread.sleepForTimeInterval(0.05)
    throw Error.TestError
}

async$ {
    try await${ willThrow }
}({(_, error) in
    expect(error).to(beTruthy())
})

强引用循环

根据 闭包的强引用循环

如果将闭包赋给类实例的一个属性,并且闭包体捕获了该实例,也可能发生强引用循环。这种捕获可能是因为闭包体访问了实例的属性,例如 self.someProperty,或者因为闭包调用了实例的方法,例如 self.someMethod()。在这些情况下,这些访问导致闭包“捕获”self,创建一个强引用循环。

在顶级闭包的开头添加捕获列表可能会有所帮助。请查看示例项目以获取更多示例。

async {[weak self] in
    self?.doSomething()
}

许可证

Async 可在 MIT 许可证下使用。有关更多信息,请参阅 LICENSE 文件。