Taskig 0.2.5

Taskig 0.2.5

Thomas Sempf 维护。



Taskig 0.2.5

Taskig: Evil Genius Task Management for Swift

CI Status Version License Platform Swift

一个受到async/await启发的库,让Swift中的异步编程变得轻松愉快!

Taskig使得在背景或主线程上执行代码变得简单,然后通过async/await方法组合这些任务。Taskig深受AsyncTask(《https://github.com/zhxnlai/AsyncTask》)的启发。

特性

  • Taskig是可组合的,允许您构建复杂的流程。
  • Taskig支持原生do-catchtry形式的错误处理。
  • Taskig是面向协议的,您可以将任何对象转换为Task。

没有Taskig

// submit a task to the global queue for background execution
DispatchQueue.global(qos: .userInteractive).async {
    let enhancedImage = self.applyImageFilter(image) // expensive operation taking a few seconds

    // update UI on the main queue
    DispatchQueue.main.async {
        self.imageView.image = enhancedImage

        UIView.animateWithDuration(0.3, animations: {
            self.imageView.alpha = 1
        }) { completed in
            // add code to happen next here
        }
    }
}

有Taskig

Task.async {
    let enhancedImage = self.applyImageFilter(image)

    Task.async(executionQueue: .main) { self.imageView.image = enhancedImage }

    UIView.animateTask(withDuration: 0.3) { self.label.alpha = 1 }.await()

    // add code to happen next here
}

它可以甚至允许您扩展现有类型

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

安装

CocoaPods

您可以通过CocoaPods来安装Taskig。要安装它,只需将以下行添加到Podfile中:

pod "Taskig"

使用方法

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

// synchronous API wrapped in task
func encrypt(message: String) -> Task<String> {
    return Task {
        encrypt(message)
    }
}

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

要获取Task的结果,请使用asyncawaitasync类似于dispatch_async,您可以提供一个完成处理程序。相反,await会阻塞当前线程并等待任务完成。为了避免在主线程上发生死锁,Taskig包含一个前置条件检查,如果您在主线程上尝试调用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()

当您创建任务时,可以指定任务应在哪个队列上执行。在内部,Taskig使用调度队列执行任务,因此所有标准调度队列都可用于执行:背景、工具、用户启动、用户交互和主,但您也可以使用针对应用程序特定的队列。

Task<Void>(executionQueue: .main) {
    print("On Main Thread")
    //Update UI here
}

Task<Int>(executionQueue: .background) { () -> Int in
    // Calculate something in the background
    return 42
}

任务组合

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

Task {
    print(“downloading image”)
    var image = downloadImage.await()
    imageView.updateWithImage(image).await()
    
    print(“processing image”)
    image = processImage(image).await()
    imageView.updateWithImage(image).await()
    
    print(“finished”)
}.async()

任务集合

Taskig也支持任务集合、字典和序列。在它们上面,您可以调用awaitFirstawaitAll以并行执行它们

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

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

您可以使用并发参数来控制并发并行任务的量

let numbersStrings = (0...900).map{ String($0) }

// Maximum of 5 parallel tasks
let all = numbersStrings.map(encrypt).awaitAll(concurrency: 5)

错误处理

Swift提供了一级支持错误处理。在Taskig中,ThrowableTask采取一个抛出闭包并将错误传播开来。

extension String: Error {}

func toStringExceptZero(number: Int) -> ThrowableTask<String> {
    return ThrowableTask<String> {
        guard number != 0 else {
            throw "FoundZero"
        }
    
        return "\(number)"
    }
}

do {
    try toStringExceptZero(number: 0).await()
} catch {
    // Prints "FoundZero" error
    print(error)
}

或者,您可以使用awaitResult()获取一个结果枚举,它可以是带有任务结果值的.success(value)或带有任务错误的.failure(error)

if case let .failure(error) = toStringExceptZero(number: 0).awaitResult() {
    print(error)
}

扩展任务

Taskig是面向协议的;它定义了TaskTypeThrowableTaskType,并使用协议扩展提供了默认的asyncawaitResultawait实现。换句话说,这些协议很容易实现,并且可以在任何符合它们的对象上进行await。能够扩展任务使它们更加强大,因为它允许任务封装状态和行为。

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

extension URL: ThrowableTaskType {
    typealias ReturnType = (Data, HTTPURLResponse)
    
    public var executionQueue: DispatchQueue { return DispatchQueue.global() }

    public func action(completion: @escaping (TaskResult<(Data, HTTPURLResponse)>) -> Void) {
        URLSession.shared.dataTask(with: self) { (data, response, error) in
            guard error == nil else {
                completion(.failure(error!))
                return
            }
        
            completion(.success((data!, response as! HTTPURLResponse)))
        }.resume()
    }
}

此扩展使我们能够编写以下代码

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

取消支持

ThrowableTaskType任务可通过CancellableTaskType协议支持取消。已取消的任务将引发一个CancellableTaskError.taskWasCancelled错误。已有的ThrowableTask实现已支持此功能。

var task = ThrowableTask<String> { () -> String in
    return "Foobar"
}

task.isCancelled = true

do {
    try task.await()
} catch {
    // CancellableTaskError.taskWasCancelled thrown
    print(error)
}

作者

Thomas Sempf

许可协议

Taskig处于MIT许可协议之下。有关更多信息,请参阅LICENSE文件。