在主线程中使用完成处理程序设置后台操作的顺序
Set order for background operations with completion handler in main thread
每次应用程序启动时,我都会在后台线程上执行以下方法:
func setup() {
loadPlayers()
loadTeams()
}
这些方法中的每一个都会调用一个 webService,这也是在后台线程中完成的,并且解析 JSON 接收到的数据以将数据加载到内存中。由于某些原因,这些解析数据的过程是在主线程中完成的。
球队是由球员组成的,所以我必须在加载球队之前设置球员的所有信息。我该怎么做?我尝试了以下代码,但在加载所有播放器之前仍会调用 loadTeams()
。
func setup() {
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.loadPlayers()
})
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.loadTeams()
})
}
听上去,您的 loadPlayers()
和 loadTeams()
函数是异步发生的。因此,使用 dispatch_sync
并不重要,因为函数会立即 return,dispatch_sync
也会立即 return。
,您需要自己对这些函数进行回调。我想你正在使用的 'webService' 无论如何都会实现某种回调系统。
例如,您希望函数执行如下操作:
func loadPlayers(callback: () -> ()) {
// I don't know what API you're using, but it must implement some form of callback system...
doAsynchronousNetworkTaskWithCompletion({success in
callback()
})
}
然后您可以简单地将这些任务分派到后台队列,使用回调对下一个任务进行排队。例如:
func setup() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.loadPlayers({
self.loadTeams({
dispatch_async(dispatch_get_main_queue(), {
// do UI update
})
})
})
})
}
此方法的唯一问题是您将开始创建厄运金字塔,这不利于可读性。
为了解决这个问题,您可以使用 dispatch_group
安排一个完成块在给定数量的任务完成时触发。由于您的任务是异步的,因此您必须使用函数 dispatch_group_enter()
和 dispatch_group_leave()
手动增加和减少任务的数量 运行ning.
例如:
func setup() {
let group = dispatch_group_create()
dispatch_group_enter(group) // Increment the number of tasks in the group
loadShirts({
dispatch_group_leave(group) // Decrement the number of tasks in the group
print("finished shirts")
})
dispatch_group_enter(group)
loadStadiums({
dispatch_group_leave(group)
print("finished stadiums")
})
dispatch_group_enter(group)
loadPlayers({
dispatch_group_leave(group)
print("finished players")
})
// gets fired when the number of tasks in the group reaches zero.
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.loadTeams({
dispatch_async(dispatch_get_main_queue(), {
// do UI update
print("finished")
})
})
})
}
还值得注意的是,使用 dispatch_sync
从主队列到后台队列并不能保证任务将 运行 在后台线程上。
因为您在执行此操作时会阻塞主线程,所以 GCD 通常会通过简单地 运行 将代码放在主线程上进行优化(因为转移到另一个线程的成本很高)。 See here for more info.
因此,您希望尽可能使用 dispatch_async
并在后台操作 本身 中进行同步,尽管这对您的情况并不重要,因为您的任务是反正是异步的。
每次应用程序启动时,我都会在后台线程上执行以下方法:
func setup() {
loadPlayers()
loadTeams()
}
这些方法中的每一个都会调用一个 webService,这也是在后台线程中完成的,并且解析 JSON 接收到的数据以将数据加载到内存中。由于某些原因,这些解析数据的过程是在主线程中完成的。
球队是由球员组成的,所以我必须在加载球队之前设置球员的所有信息。我该怎么做?我尝试了以下代码,但在加载所有播放器之前仍会调用 loadTeams()
。
func setup() {
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.loadPlayers()
})
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.loadTeams()
})
}
听上去,您的 loadPlayers()
和 loadTeams()
函数是异步发生的。因此,使用 dispatch_sync
并不重要,因为函数会立即 return,dispatch_sync
也会立即 return。
例如,您希望函数执行如下操作:
func loadPlayers(callback: () -> ()) {
// I don't know what API you're using, but it must implement some form of callback system...
doAsynchronousNetworkTaskWithCompletion({success in
callback()
})
}
然后您可以简单地将这些任务分派到后台队列,使用回调对下一个任务进行排队。例如:
func setup() {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.loadPlayers({
self.loadTeams({
dispatch_async(dispatch_get_main_queue(), {
// do UI update
})
})
})
})
}
此方法的唯一问题是您将开始创建厄运金字塔,这不利于可读性。
为了解决这个问题,您可以使用 dispatch_group
安排一个完成块在给定数量的任务完成时触发。由于您的任务是异步的,因此您必须使用函数 dispatch_group_enter()
和 dispatch_group_leave()
手动增加和减少任务的数量 运行ning.
例如:
func setup() {
let group = dispatch_group_create()
dispatch_group_enter(group) // Increment the number of tasks in the group
loadShirts({
dispatch_group_leave(group) // Decrement the number of tasks in the group
print("finished shirts")
})
dispatch_group_enter(group)
loadStadiums({
dispatch_group_leave(group)
print("finished stadiums")
})
dispatch_group_enter(group)
loadPlayers({
dispatch_group_leave(group)
print("finished players")
})
// gets fired when the number of tasks in the group reaches zero.
dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
self.loadTeams({
dispatch_async(dispatch_get_main_queue(), {
// do UI update
print("finished")
})
})
})
}
还值得注意的是,使用 dispatch_sync
从主队列到后台队列并不能保证任务将 运行 在后台线程上。
因为您在执行此操作时会阻塞主线程,所以 GCD 通常会通过简单地 运行 将代码放在主线程上进行优化(因为转移到另一个线程的成本很高)。 See here for more info.
因此,您希望尽可能使用 dispatch_async
并在后台操作 本身 中进行同步,尽管这对您的情况并不重要,因为您的任务是反正是异步的。