GCD函数乱序调用
问题描述:
我不明白为什么下面的代码被乱序调用。它只是为了公开它们被调用的顺序而写的。这很重要,因为我正在使用这些Web服务调用,它们应该彼此等待,而他们不是。所以,这可能只是我对如何使用GCD的概念。GCD函数乱序调用
var group: dispatch_group_t = dispatch_group_create()
var groupTwo: dispatch_group_t = dispatch_group_create()
var queue: dispatch_queue_t = dispatch_get_main_queue()
dispatch_group_notify(groupTwo, queue) {() -> Void in
print("3rd") // Should be called 3rd
}
dispatch_group_enter(group)
print("1st") // Should be called 1st
dispatch_group_leave(group)
dispatch_group_notify(group, queue) {() -> Void in
dispatch_group_enter(groupTwo)
print("2nd") // Should be called 2nd
dispatch_group_leave(groupTwo)
}
这是命令它打印在:
1st
3rd
2nd
为什么是顺序错了吗?不应该3rd
只叫一次dispatch_group_leave(groupTwo)
叫?为什么事先被调用?我认为这是dispatch_group_notify()
被用于。
编辑:对不起,我只是修复了组名。起初忘了编辑一些。
答
dispatch_group_notify(groupTwo, queue) {() -> Void in
print("3rd") // Should be called 3rd
}
dispatch_group_notify
将在组为空时将第一个块提交给队列。最初,该组是空的。因此,它将异步提交给主队列。
这里
dispatch_group_enter(group)
print("1st") // Should be called 1st
dispatch_group_leave(group)
您有效地打印到控制台上的主队列 - 此打印
1st
这里
dispatch_group_notify(group, queue) {() -> Void in
dispatch_group_enter(groupTwo)
print("2nd") // Should be called 2nd
dispatch_group_leave(groupTwo)
}
你异步提交其被排队的第二块在第一块之后。
现在,第一块执行,打印
3rd
最后,第二块打印:
2nd
答
这听起来像你需要等待两个或多个远程调用的结果然后才能发出最终的远程呼叫。比方说,你有这些参数,这将通过远程调用来填充两个属性:
var a:String? = nil // populated asynchronously
var b:String? = nil // populated asynchronously
然后,假设你的远程调用是这样的:
func getParameterA(completionHandler:(String) -> Void) {
print("Getting parameter A")
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
NSThread.sleepForTimeInterval(0.2)
completionHandler("A")
print("Got parameter A")
}
}
func getParameterB(completionHandler:(String) -> Void) {
print("Getting parameter B")
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
NSThread.sleepForTimeInterval(0.1)
completionHandler("B")
print("Got parameter B")
}
}
func getResult(a:String, b:String, completionHandler:(String) -> Void) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {
NSThread.sleepForTimeInterval(0.05)
completionHandler("This is the result of \(a) and \(b)")
}
}
在现实中,他们将远程调用而不是睡在后台线程上。
然后,你的代码来填充a
和b
看起来就像这样:
// the blocks in the parameter group are responsible for setting a and b
let parameterGroup = dispatch_group_create()
dispatch_group_enter(parameterGroup)
getParameterA() { parameter in
// set the value of a asynchronously
self.a = parameter
dispatch_group_leave(parameterGroup)
}
dispatch_group_enter(parameterGroup)
getParameterB() { parameter in
// set the value of b asynchronously
self.b = parameter
dispatch_group_leave(parameterGroup)
}
最后,你可以用dispatch_group_notify
定义最终完成处理程序只执行一次,有没有更多的任务parameterGroup
:
let finalGroup = dispatch_group_create()
dispatch_group_enter(finalGroup)
dispatch_group_notify(parameterGroup, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
self.getResult(self.a!, b:self.b!) { result in
print("-- \(result)")
dispatch_group_leave(finalGroup)
}
}
dispatch_group_wait(finalGroup, DISPATCH_TIME_FOREVER)
finalGroup
不是严格必要的,但我需要它来得到范例在XCTest
内工作。
输出将是这样的:
Getting parameter A
Getting parameter B
Got parameter B
Got parameter A
-- This is the result of A and B
,你做'dispatch_group_enter(groupTwo)块,如果'groupTwo'为空,并在第一时间之后执行的第一个'dispatch_group_notify'检查'版画“第三“一旦发现它是。 – dan
我没有想到'dispatch_group_notify'甚至会在dispatch_group_leave之前被调用。有没有更好的方法来完成我想要做的事情? – chicobermuda
这是不是很清楚你想做什么。我假设你为了这个问题抽象了所有的细节,但是很难说出你应该做什么。 – dan