此项目已停止维护。

Async

Carthage compatible CocoaPods compatible

现在不仅仅是 Swift 中 Grand Central Dispatch (GCD) 异步调度的语法糖了

Async 语法糖看起来像这样

Async.userInitiated {
	10
}.background {
	"Score: \($0)"
}.main {
	label.text = $0
}

即使 Swift 3.0 之后的 GCD 已经有了相对不错的语法,请将上面的代码与下面进行比较:

DispatchQueue.global(qos: .userInitiated).async {
	let value = 10
	DispatchQueue.global(qos: .background).async {
		let text = "Score: \(value)"
		DispatchQueue.main.async {
			label.text = text
		}
	}
}

AsyncGroup 语法糖看起来像这样

let group = AsyncGroup()
group.background {
    print("This is run on the background queue")
}
group.background {
    print("This is also run on the background queue in parallel")
}
group.wait()
print("Both asynchronous blocks are complete")

安装

Swift Package Manager

在 Xcode 11 中添加到你的项目

File > Swift Packages > Add Package Dependency (文件 > Swift Packages > 添加 Package 依赖)

在 Package.swift 中添加为依赖
dependencies: [
    .package(url: "https://github.com/duemunk/Async", from: "2.1.0"),
],

CocoaPods

use_frameworks!
pod "AsyncSwift"

Carthage

github "duemunk/Async"

优势

  1. 通过链式调用避免代码缩进
  2. 参数和返回类型减少了作用域污染

你可以做的事情

支持现代队列类

Async.main {}
Async.userInteractive {}
Async.userInitiated {}
Async.utility {}
Async.background {}

随意链式调用任意数量的 block

Async.userInitiated {
	// 1
}.main {
	// 2
}.background {
	// 3
}.main {
	// 4
}

存储引用以便后续链式调用

let backgroundBlock = Async.background {
	print("This is run on the background queue")
}

// Run other code here...

// Chain to reference
backgroundBlock.main {
	print("This is run on the \(qos_class_self().description) (expected \(qos_class_main().description)), after the previous block")
}

自定义队列

let customQueue = DispatchQueue(label: "CustomQueueLabel", attributes: [.concurrent])
let otherCustomQueue = DispatchQueue(label: "OtherCustomQueueLabel")
Async.custom(queue: customQueue) {
	print("Custom queue")
}.custom(queue: otherCustomQueue) {
	print("Other custom queue")
}

延迟调度 block

let seconds = 0.5
Async.main(after: seconds) {
	print("Is called after 0.5 seconds")
}.background(after: 0.4) {
	print("At least 0.4 seconds after previous block, and 0.9 after Async code is called")
}

取消尚未调度的 block

// Cancel blocks not yet dispatched
let block1 = Async.background {
	// Heavy work
	for i in 0...1000 {
		print("A \(i)")
	}
}
let block2 = block1.background {
	print("B – shouldn't be reached, since cancelled")
}
Async.main {
	// Cancel async to allow block1 to begin
	block1.cancel() // First block is _not_ cancelled
	block2.cancel() // Second block _is_ cancelled
}

等待 block 完成 – 一种在后台任务完成后在当前队列上继续执行的简便方法

let block = Async.background {
	// Do stuff
}

// Do other stuff

block.wait()

它是如何工作的

它的工作方式是使用 OS X 10.10 和 iOS 8 中引入的 GCD 的新通知 API。每个链式 block 都在前一个队列完成后被调用。

let previousBlock = {}
let chainingBlock = {}
let dispatchQueueForChainingBlock = ...

// Use the GCD API to extend the blocks
let _previousBlock = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, previousBlock)
let _chainingBlock = dispatch_block_create(DISPATCH_BLOCK_INHERIT_QOS_CLASS, chainingBlock)

// Use the GCD API to call back when finishing the "previous" block
dispatch_block_notify(_previousBlock, dispatchQueueForChainingBlock, _chainingBlock)

链式调用的语法部分是通过在 Async 对象上拥有类方法来实现的,例如 Async.main {},它返回一个结构体。该结构体具有匹配的方法,例如 theStruct.main {}

已知错误

现代 GCD 队列在 iOS 模拟器中无法按预期工作。请参阅问题 13, 22

已知改进

dispatch_block_t 无法扩展。解决方法:将 dispatch_block_t 包装在一个结构体中,该结构体将 block 作为属性。

Apply

还有一个用于 dispatch_apply() 的包装器,用于快速并行化 for 循环。

Apply.background(100) { i in
	// Do stuff e.g. print(i)
}

请注意,此函数在 block 运行 100 次后返回,即它不是异步的。对于异步行为,请将其包装在 Async block 中,例如 Async.background { Apply.background(100) { ... } }

AsyncGroup

AsyncGroup 方便处理异步 block 组。

使用 GCD 的多个调度 block

let group = AsyncGroup()
group.background {
    // Run on background queue
}
group.utility {
    // Run on utility queue, in parallel to the previous block
}
group.wait()

所有现代队列类

group.main {}
group.userInteractive {}
group.userInitiated {}
group.utility {}
group.background {}

自定义队列

let customQueue = dispatch_queue_create("Label", DISPATCH_QUEUE_CONCURRENT)
group.custom(queue: customQueue) {}

等待组完成

let group = AsyncGroup()
group.background {
    // Do stuff
}
group.background {
    // Do other stuff in parallel
}
// Wait for both to finish
group.wait()
// Do rest of stuff

自定义异步操作

let group = AsyncGroup()
group.enter()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    // Do stuff
    group.leave()
}
group.enter()
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    // Do other stuff in parallel
    group.leave()
}
// Wait for both to finish
group.wait()
// Do rest of stuff

许可证

The MIT License (MIT)

Copyright (c) 2016 Tobias Due Munk

特此授予任何人免费获得本软件及相关文档文件(“软件”)副本的许可,以不受限制地处理本软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或出售软件副本的权利,并允许向其提供本软件的人员遵守以下条件

以上版权声明和本许可声明应包含在本软件的所有副本或重要部分中。

本软件按“原样”提供,不提供任何形式的明示或暗示保证,包括但不限于对适销性、特定用途适用性和不侵权的保证。在任何情况下,作者或版权所有者均不对任何索赔、损害或其他责任负责,无论是在合同、侵权或其他方面,因本软件或本软件的使用或与本软件有关的其他交易而引起、产生或与之相关的责任。