在主线程中使用完成处理程序设置后台操作的顺序

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 并在后台操作 本身 中进行同步,尽管这对您的情况并不重要,因为您的任务是反正是异步的。