AsyncTask 0.1.3

AsyncTask 0.1.3

测试已测试
语言语言 SwiftSwift
许可证 MIT
发布上次发布2016年6月
SPM支持SPM

赖志璇维护。



AsyncTask 0.1.3

  • 赖志璇

AsyncTask

Swift的异步编程库

特性

AsyncTask远不止Future和Promise。

  • 它是可组合的,允许你构建复杂的流程。
  • 它支持原生的do-catchtry错误处理。
  • 它是以协议为中心的,因此你可以将任何对象转换为Task。

在没有AsyncTask的情况下

// get a global concurrent queue
let queue = dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE, 0)
// submit a task to the queue for background execution
dispatch_async(queue) {
    let enhancedImage = self.applyImageFilter(image) // expensive operation taking a few seconds
    // update UI on the main queue
    dispatch_async(dispatch_get_main_queue()) {
        self.imageView.image = enhancedImage
        UIView.animateWithDuration(0.3, animations: {
            self.imageView.alpha = 1
        }) { completed in
            // add code to happen next here
        }
    }
}

在有AsyncTask的情况下

Task {
    let enhancedImage = self.applyImageFilter(image)
    Task {self.imageView.image = enhancedImage}.async(.Main)
    let completed = UIView.animateWithDurationAsync(0.3) { self.label.alpha = 1 }.await(.Main)
    // add code to happen next here
}.async()

它甚至允许你扩展现有类型

let (data, response) = try! NSURL(string: "www.google.com")!.await()

安装

教程

使用方法

In AsyncTask,一个Task代表异步操作最终的成果,就像在其他库中的Future和Promise。它可以包装同步和异步API。要创建一个Task,使用闭包进行初始化。要使其可重用,编写返回任务的函数。

// synchronous API
func encrypt(message: String) -> Task<String> {
    return Task {
        encrypt(message)
    }
}
// asynchronous API
func get(URL: NSURL) -> Task<(NSData?, NSURLResponse?, NSError?)> {
    return Task {completionHandler in
        NSURLSession().dataTaskWithURL(URL, completionHandler: completionHandler).resume()
    }
}

为了获取Task的结果,使用asyncawaitasync就像dispatch_async,你可以提供一个完成处理器。相对地,await会阻塞当前线程并等待任务完成。

// async
encrypt(message).async { ciphertext in /* do somthing */ }
get(URL).async {(data, response, error) in /* do somthing */ }

// await
let ciphertext = encrypt(message).await()
let (data, response, error) = get(URL).await()

组合任务

你可以使用多个await表达式来确保每个语句在执行下一个语句之前完成

Task {
    print(“downloading image”)
    var image = UIImage(data: downloadImage.await())!
    updateImageView(image).await(.Main)
    print(“processing image”)
    image = processImage(image).await()
    updateImageView(image).await(.Main)
    print(“finished”)
}.async()

你还可以在任务集合上调用awaitFirstawaitAll以并行执行它们

let replicatedURLs = ["https://web1.swift.org", "https://web2.swift.org"]
let first = replicatedURLs.map(get).awaitFirst()

let messages = ["1", "2", "3"]
let all = messages.map(encrypt).awaitAll()

错误处理

Swift为错误处理提供了first-class的支持。在AsyncTask中,一个ThrowableTask接受一个抛出闭包并传播错误。

func load(path: String) -> ThrowableTask<NSData> {
    return ThrowableTask {
        switch path {
        case "profile.png":
            return NSData()
        case "index.html":
            return NSData()
        default:
            throw Error.NotFound
        }
    }
}

expect{try load("profile.png").await()}.notTo(throwError())
expect{try load("index.html").await()}.notTo(throwError())
expect{try load("random.txt").await()}.to(throwError())

扩展任务

AsyncTask 是一种基于协议的类;它定义了 TaskTypeThrowableTaskType,并使用协议扩展提供了 asyncawait 的默认实现。换句话说,这些协议易于实现,并且您可以在任何符合它们的对象上使用 await。任务能够扩展功能,因为它允许任务封装状态和行为。

在以下示例中,通过将 NSURL 扩展到 TaskType,我们将数据获取作为 NSURL 类的一部分。要符合 TaskType 协议,只需指定一个动作和返回类型。

extension NSURL : ThrowableTaskType {

    public typealias ReturnType = (NSData, NSURLResponse)

    public func action(completion: Result<ReturnType> -> ()) {
        ThrowableTask<ReturnType> {
            let session = NSURLSession(configuration: .ephemeralSessionConfiguration())
            let (data, response, error) = Task { callback in session.dataTaskWithURL(self, completionHandler: callback).resume()}.await()
            guard error == nil else { throw error! }
            return (data!, response!)
        }.asyncResult(completion: completion)
    }

}

本扩展允许我们编写如下代码

let (data, response) = try! NSURL(string: "www.google.com")!.await()

任务可以表示更复杂的活动,甚至包括涉及 UI 的活动。以下示例中,我们使用 ImagePickerTask 来启动 UIImagePickerViewController 并等待用户选择图片。一旦用户选择了图片或点击了取消按钮,视图控制器将消失,任务将返回所选择的图片。

class ImagePickerDemoViewController: UIViewController {

    let imageView = UIImageView()

    func launchImagePicker() {
        Task {
            do {
                let data = try ImagePickerTask(viewController: self).await()
            } catch Error.PhotoLibraryNotAvailable {
                alert("Photo Library is Not Available")
            }
            guard let image = data?[UIImagePickerControllerOriginalImage] as? UIImage else {
                self.imageView.image = nil
                return
            }
            self.imageView.image = image
        }.async()
    }

}

ImagePickerTask 能够知道用户是否选择了图片或取消了选择,因为它是 UIImagePickerViewController 的代理。有关更多详情,请参阅其 实现 和示例文件夹。

示例

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

您也可以查看 测试用例

作者

李志炫,[email protected]

许可证

AsyncTask 在 MIT 许可下提供。有关更多信息,请参阅 LICENSE 文件。