Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/94.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在主线程中使用完成处理程序设置后台操作的顺序_Ios_Multithreading_Swift_Grand Central Dispatch - Fatal编程技术网

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

Ios 在主线程中使用完成处理程序设置后台操作的顺序,ios,multithreading,swift,grand-central-dispatch,Ios,Multithreading,Swift,Grand Central Dispatch,每次应用程序启动时,我都会在后台线程上执行以下方法: func setup() { loadPlayers() loadTeams() } 这些方法中的每一个都调用一个webService(也在后台线程中完成),并解析接收到的JSON以将数据加载到内存中。出于某种原因,这些数据解析过程是在主线程中完成的 球队是由球员组成的,所以我必须在加载球队之前设置球员的所有信息。我怎么做这个?我尝试了以下代码,但在加载所有玩家之前仍会调用loadTeams() func setup() {

每次应用程序启动时,我都会在后台线程上执行以下方法:

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\u sync
,则无所谓,因为函数将立即返回,
dispatch\u sync
也将立即返回

,您需要自己实现对这些函数的回调。我想你正在使用的“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
                })
            })
        })
    })

}
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\u group
来计划在给定数量的任务完成时触发完成块。由于任务是异步的,因此必须使用函数
dispatch\u group\u enter()
dispatch\u group\u leave()
手动增加和减少正在运行的任务数

例如:

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
                })
            })
        })
    })

}
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")
            })
        })
    })
}

还值得注意的是,从主队列向后台队列使用
调度\u sync
,并不保证任务将在后台线程上运行

因为这样做会阻塞主线程,所以GCD通常会通过简单地在主线程上运行代码来进行优化(因为传输到另一个线程是昂贵的)


因此,您希望尽可能地使用
dispatch\u async
,并在后台操作中进行同步,尽管这在您的情况下并不重要,因为您的任务无论如何都是异步的。

从听起来的情况来看,您的
loadPlayers()
loadTeams()
函数是异步执行的。因此,如果使用的是
dispatch\u sync
,则无所谓,因为函数将立即返回,
dispatch\u sync
也将立即返回

,您需要自己实现对这些函数的回调。我想你正在使用的“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
                })
            })
        })
    })

}
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\u group
来计划在给定数量的任务完成时触发完成块。由于任务是异步的,因此必须使用函数
dispatch\u group\u enter()
dispatch\u group\u leave()
手动增加和减少正在运行的任务数

例如:

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
                })
            })
        })
    })

}
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")
            })
        })
    })
}

还值得注意的是,从主队列向后台队列使用
调度\u sync
,并不保证任务将在后台线程上运行

因为这样做会阻塞主线程,所以GCD通常会通过简单地在主线程上运行代码来进行优化(因为传输到另一个线程是昂贵的)


因此,您希望尽可能使用
dispatch\u async
,并在后台操作本身内同步,尽管这在您的情况下并不重要,因为您的任务无论如何都是异步的。

您应该在
loadPlayers()
完成时调用回调方法(或块)。您可以在回调方法中调用
loadTeams()
。当
loadPlayers()
完成时,您应该调用回调方法(或块)。您可以通过callback方法调用
loadTeams()
。谢谢@originaluser2。这里的问题是,在
loadTeams()
之前,我需要执行多个方法。假设我还有
loadStadiums()
loadShirts()
,它们可以与
loadPlayers()
同时执行,并且这三种方法必须已经完成才能执行
loadTeams()
。我可以使用回调解决方案,但这不允许同时使用多个方法。@Matias我已经更新了我的答案,说明了如何做到这一点,谢谢@originaluser2。这里的问题是,在
loadTeams()
之前,我需要执行多个方法。假设我还有
loadStadiums()
loadShirts()
,它们可以与
loadPlayers()
同时执行,并且这三种方法必须已经完成才能执行
loadTeams()
。我可以使用回调解决方案,但这不允许同时使用多个方法。@Matias我已经更新了我的答案,说明了如何做到这一点