使用GCD在iOS中进行多任务处理

多任务处理使我们可以同时运行许多任务。 GCD(Grand Central Dispatch)是在iOS中实现多任务处理的最简单方法。 我们将任务添加到调度队列,这些任务又在多个线程上同时执行。 我们可以在后台线程上执行诸如下载或搜索之类的耗时任务,这将使UI响应用户。

iOS提供了用于在后台线程上执行任务的全局调度队列,以及用于在main / UI线程上执行任务的调度队列。

我们还可以创建自己的任务执行队列。

  let queue = DispatchQueue(标签:“ com.gcd.simpleQueue”) 

我们需要为队列提供唯一的标签。 它可以是任何字符串,但是约定是使用反向域名(反向DNS)。 要执行任务,我们必须将其称为.async.sync 方法。 任务不过是要执行的代码块。

  queue.async { 
_ in 1…5 {
打印(“ clap..clap..👏”)
}
}

输出:

  拍手..拍手..👏 
拍手..拍手..👏
拍手..拍手..👏
拍手..拍手..👏
拍手..拍手..👏

调度队列上的.async.sync方法告诉系统如何执行任务。 让我们用下面给出的示例进行检查。

  func executeSync(){ 让队列= DispatchQueue(label:“ com.gcd.simpleQueue”) print(“ Start Race:”) //在同步模式下在队列上运行 
queue.sync {
因为我在0 .. <5 {
print(“ 🐢 @ \(i + 1)公里。”)
}
} //在UI线程上运行
因为我在0 .. <5 {
print(“ 🐇 @ \(i + 1)公里。”)
}
}

输出:

for…在。之后编写的循环同步 等待直到.sync块中的for … loop执行完成。 因此,兔子要等到乌龟完成比赛后才能开始比赛。

  开始比赛: 
🐢 @ 1公里。
🐢 @ 2公里。
🐢 @ 3公里。
🐢 @ 4公里。
🐢 @ 5公里。
🐇 @ 1公里。
🐇 @ 2公里。
🐇 @ 3公里。
🐇 @ 4公里。
🐇 @ 5公里。

队列调度任务上的.sync方法执行,直到块完成其执行后才返回。 因此,在块的执行完成之前,不会执行在块之后编写的代码。

另一方面.async 方法在分派后立即从块返回。 在分发块继续执行之后编写的代码将执行,而无需等待该块完成其执行。

  func executeAsync(){ 

let queue = DispatchQueue(label:“ com.gcd.simpleQueue”)
打印(“开始比赛:”)

//以异步模式在队列上运行
queue.async {
因为我在0 .. <5 {
print(“ 🐢 @ \(i + 1)公里。”)
}
} //在UI线程上运行
因为我在0 .. <5 {
print(“ 🐇 @ \(i + 1)公里。”)
}
}

输出:

在异步模式下,将调用队列中的.async方法,并且编译器将继续执行下一行代码,它不会等待.async块完成其执行。 在这里,兔子在乌龟之后立即开始奔跑,兔子不会等待乌龟完成比赛。

  开始比赛: 
🐇 @ 1公里。
🐢 @ 1公里。
🐇 @ 2公里。
🐢 @ 2公里。
🐇 @ 3公里。
🐇 @ 4公里。
🐢 @ 3公里。
🐇 @ 5公里。
🐢 @ 4公里。
🐢 @ 5公里。

我们可以执行提交的任务以串行或并行方式进行排队。 默认情况下,提交到队列的任务将按顺序执行 。 在串行模式下,队列中的任务只有在队列中先前分派的任务完成执行后才能执行。

  func serialExecution(){ 
let queue = DispatchQueue(label:“ com.gcd.simpleQueue”)
print(“开始竞赛:”) // Task1
queue.async {
因为我在0 .. <5 {
print(“ 🐢 @ \(i + 1)公里。”)
}
} // Task2
queue.async {
因为我在0 .. <5 {
print(“ 🐇 @ \(i + 1)公里。”)
}
}
}

输出:

我们有两个任务提交到队列, Task1具有for…与乌龟循环 ,而Task2具有for…与兔子循环 。 该队列将首先分派Task1,并且由于它是串行队列,因此Task2必须直到Task1的执行完成为止。 一旦执行Task1完成,队列将调度Task2进行执行。

  开始比赛: 
🐢 @ 1公里。
🐢 @ 2公里。
🐢 @ 3公里。
🐢 @ 4公里。
🐢 @ 5公里。
🐇 @ 1公里。
🐇 @ 2公里。
🐇 @ 3公里。
🐇 @ 4公里。
🐇 @ 5公里。

我们可以创建并发队列以执行任务。 我们必须将queue的.attributes属性设置为并发。 在并发模式下,队列中的任务会陆续分派,并立即开始执行,任务以任何顺序完成它们的执行。 这里不能保证执行顺序。

  func parallelExecution (){ 让队列= DispatchQueue(标签:“ com.gcd.simpleQueue”,qos:.userInitiated,属性:.concurrent) 

print(“开始竞赛:”) // Task1
queue.async {
因为我在0 .. <5 {
print(“ 🐢 @ \(i + 1)公里。”)
}
} // Task2
queue.async {
因为我在0 .. <5 {
print(“ 🐇 @ \(i + 1)公里。”)
}
}
}

输出:

并发模式中的队列立即分派任务。 与串行模式不同, Task2不会等待Task1完成执行。

  开始比赛: 
🐇 @ 1公里。
🐢 @ 1公里。
🐇 @ 2公里。
🐢 @ 2公里。
🐇 @ 3公里。
🐢 @ 3公里。
🐇 @ 4公里。
🐢 @ 4公里。
🐇 @ 5公里。
🐢 @ 5公里。

有些任务比其他任务更重要,因此我们必须确保将首先执行它们。 我们可以通过为它们分配优先级来实现。 在主线程/ UI线程上运行的任务始终具有较高的优先级,因为它们使应用程序保持响应速度,而在后台线程上运行的任务则具有最低的优先级。 最终,所有任务均完成其执行,但优先级决定哪个任务将首先完成。

优先级列表如下,第一个表示最高优先级,最后一个表示最低优先级。

  .userInteractive 
.userInitiated
。默认
。效用
。背景
.unspecified

如果未指定优先级,则将考虑默认优先级。

  func checkQos(){ let queue1 = DispatchQueue(label:“ com.gcd.simpleQueue1”,qos:.userInitiated) let queue2 = DispatchQueue(label:“ com.gcd.simpleQueue2”,qos:.background) print(“ Start Race :“) 

queue1.async {
因为我在0 .. <5 {
print(“ 🐢 @ \(i + 1)公里。”)
}
} queue2.async {
因为我在0 .. <5 {
print(“ 🐇 @ \(i + 1)公里。”)
}
}
}

输出:

队列 1队列2的优先级分别为.userInitiated.background 。 用户启动的任务始终比后台任务具有更高的优先级。 因此, queue1中的任务将比queue2中的任务更早执行。

  🐢 @ 1公里。 
🐇 @ 1公里。
🐢 @ 2公里。
🐢 @ 3公里。
🐇 @ 2公里。
🐢 @ 4公里。
🐇 @ 3公里。
🐢 @ 5公里。
🐇 @ 4公里。
🐇 @ 5公里。

不必创建自己的任务执行队列。 iOS为我们提供了一些默认的队列集,可用于执行任务。 如果我们想在后台执行任务,例如下载文件,加载数据或执行搜索,则可以使用全局队列。

主队列允许我们在主/ UI线程上执行任务。 与UI更新相关的任务可以在主队列上运行。

  func globalQueue(){ 

让globalQueue = DispatchQueue.global()

globalQueue.async {
因为我在0 .. <5 {
打印(“ \(i)”)
}
}
}

我们可以通过指定QoS来访问具有特定优先级的全局队列。

  让globalQueue = DispatchQueue.global(qos:.userInitiated) 

我们不应在后台队列或除主队列以外的队列上执行与UI相关的操作,否则编译器将显示警告。 我们需要主队列来执行UI操作。 我们这样访问主队列

  DispatchQueue.main 

下面的代码更改了主队列中视图的背景颜色。

  func mainQueue(){ 
DispatchQueue.main.async {
self.view.backgroundColor = UIColor.red
}
}

有时有必要延迟执行代码。 GCD允许我们通过使用特殊方法.asyncAfter来执行相同操作 我们需要设置要延迟执行的时间。

  func delayExecution(){ 

let queue = DispatchQueue(label:“ com.gcd.simpleQueue”) let delayInteraval = DispatchTimeInterval.seconds(5) print(Date()) //延迟5秒后执行
queue.asyncAfter(截止日期:.now()+ delayInteraval){
打印(日期())
}
}

输出:

  2018-02-04 14:39:02 +0000 
2018-02-04 14:39:07 +0000

我们可以使用方法指定以秒,毫秒,微秒或纳秒为单位的延迟

.seconds(Int)、. milliseconds(Int)、. microseconds(Int)和.nanoseconds(Int)

DispatchWorkItem不过是我们可以在任何队列上执行的代码块。 无需编写代码块,我们可以创建一个工作项以执行。

  让dispatchWorkItem = DispatchWorkItem { 
print(“ WorkItem Executed”)
}

我们可以通过调用.perform()方法来执行dispatchWorkItem。 .perform()将在当前线程上执行工作项。

  dispatchWorkItem.perform() 

或者我们可以将其添加到执行队列中。

  DispatchQueue.global()。async(执行:dispatchWorkItem) 

输出:

  工作项已执行 

DispatchQueue为我们提供了一种方便的方法来同时执行相同数量的迭代任务。

  功能并发Perform(){ 
DispatchQueue.concurrentPerform(迭代次数:5){(i)在
print(“迭代:\(i)”)
}
}

输出:

  迭代次数:1 
迭代次数:3
迭代次数:0
迭代次数:4
迭代次数:2

GCD是在iOS中编写多任务代码的最简单方法。 我们可以使用它在后台线程上移动繁重的任务并减少主线程上的负载。

GCD中有许多主题需要探讨。 为了使这篇文章简单而简短,我没有涵盖所有内容,但是涵盖了所有要点。

您可以试用示例代码。 使用GCD尝试不同的事情。

请在这里留下您的反馈和建议。

谢谢,祝您编程愉快。