调度队列不等待
Dispatch queue not waiting
情况是我需要遍历多个对象并对每个对象进行网络调用。
所有网络调用完成后,我将使用从这些网络调用中收集的所有数据调用完成块。
为此,我尝试使用调度组,在网络呼叫开始时进入,在网络呼叫结束时离开:
for user in users {
dispatch_group_enter(downloadGroup)
UserManager.retrieveFriendsForUser(user, completed: { (usersFriends, fault) in
guard let usersFriends = usersFriends else {
return
}
dispatch_group_leave(downloadGroup)
})
}
然后我在等待他们完成以下内容:
dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER);
但是,它似乎并没有等待我所有的分组网络调用完成。
这是完整上下文中的所有代码;我正在遍历许多用户,然后查询他们的朋友。我希望该方法 return 他们所有的朋友合并(通过将所有结果连接到 allNonFriends 数组):
class func retrieveNonFriendsOfFriends(completed : (users : [BackendlessUser]?, fault : Fault?) -> Void) {
var allNonFriends = [BackendlessUser]()
let downloadGroup = dispatch_group_create() // 2
dispatch_group_enter(downloadGroup) // 3
UserManager.retrieveCurrentUsersFriends { (users, fault) in
guard let users = users else {
print("Server reported an error: \(fault)")
completed(users: nil, fault: fault)
return
}
for user in users {
dispatch_group_enter(downloadGroup) // 3
UserManager.retrieveFriendsForUser(user, completed: { (usersFriends, fault) in
guard let usersFriends = usersFriends else {
print("Server reported an error: \(fault)")
return
}
let nonFriends = usersFriends.arrayWithoutFriends(users)
allNonFriends += nonFriends
dispatch_group_leave(downloadGroup) // 4
})
}
}
dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER);
completed(users: allNonFriends, fault: nil)
}
每次调用dispatch_group_enter()
,都需要调用dispatch_group_leave()
;如果您调用 dispatch_group_enter()
5 次,那么您还需要调用 dispatch_group_leave()
5 次。
您为检索当前用户的好友调用了 1 次
dispatch_group_enter(downloadGroup) // 3
UserManager.retrieveCurrentUsersFriends
然后#users 在完成后调用
for user in users {
dispatch_group_enter(downloadGroup) // 3
问题 1
您没有平衡第一个检索当前用户好友的调用。
问题 2
如果 userFriends
为零,您永远不会为该用户调用 dispatch_group_leave()
。
最终的结果是你永远不会完成 dispatch_group
并且永远等待。
解决方案
dispatch_group_enter(downloadGroup) // 3
UserManager.retrieveCurrentUsersFriends { (users, fault) in
defer {
// Whether we return early or use the users we want to leave the group
// Balances the initial enter()
dispatch_group_leave(downloadGroup)
}
... process users
for user in users {
dispatch_group_enter(downloadGroup) // 3
UserManager.retrieveFriendsForUser(user, completed: { (usersFriends, fault) in
// No matter the outcome of the call we want to leave the
// dispatch_group so we don't wait forever
defer {
// Balances the enter() for each user
dispatch_group_leave(downloadGroup)
}
.... process userFriends
}
}
推荐阅读:http://commandshift.co.uk/blog/2014/03/19/using-dispatch-groups-to-wait-for-multiple-web-services/
情况是我需要遍历多个对象并对每个对象进行网络调用。
所有网络调用完成后,我将使用从这些网络调用中收集的所有数据调用完成块。
为此,我尝试使用调度组,在网络呼叫开始时进入,在网络呼叫结束时离开:
for user in users {
dispatch_group_enter(downloadGroup)
UserManager.retrieveFriendsForUser(user, completed: { (usersFriends, fault) in
guard let usersFriends = usersFriends else {
return
}
dispatch_group_leave(downloadGroup)
})
}
然后我在等待他们完成以下内容:
dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER);
但是,它似乎并没有等待我所有的分组网络调用完成。
这是完整上下文中的所有代码;我正在遍历许多用户,然后查询他们的朋友。我希望该方法 return 他们所有的朋友合并(通过将所有结果连接到 allNonFriends 数组):
class func retrieveNonFriendsOfFriends(completed : (users : [BackendlessUser]?, fault : Fault?) -> Void) {
var allNonFriends = [BackendlessUser]()
let downloadGroup = dispatch_group_create() // 2
dispatch_group_enter(downloadGroup) // 3
UserManager.retrieveCurrentUsersFriends { (users, fault) in
guard let users = users else {
print("Server reported an error: \(fault)")
completed(users: nil, fault: fault)
return
}
for user in users {
dispatch_group_enter(downloadGroup) // 3
UserManager.retrieveFriendsForUser(user, completed: { (usersFriends, fault) in
guard let usersFriends = usersFriends else {
print("Server reported an error: \(fault)")
return
}
let nonFriends = usersFriends.arrayWithoutFriends(users)
allNonFriends += nonFriends
dispatch_group_leave(downloadGroup) // 4
})
}
}
dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER);
completed(users: allNonFriends, fault: nil)
}
每次调用dispatch_group_enter()
,都需要调用dispatch_group_leave()
;如果您调用 dispatch_group_enter()
5 次,那么您还需要调用 dispatch_group_leave()
5 次。
您为检索当前用户的好友调用了 1 次
dispatch_group_enter(downloadGroup) // 3
UserManager.retrieveCurrentUsersFriends
然后#users 在完成后调用
for user in users {
dispatch_group_enter(downloadGroup) // 3
问题 1
您没有平衡第一个检索当前用户好友的调用。
问题 2
如果 userFriends
为零,您永远不会为该用户调用 dispatch_group_leave()
。
最终的结果是你永远不会完成 dispatch_group
并且永远等待。
解决方案
dispatch_group_enter(downloadGroup) // 3
UserManager.retrieveCurrentUsersFriends { (users, fault) in
defer {
// Whether we return early or use the users we want to leave the group
// Balances the initial enter()
dispatch_group_leave(downloadGroup)
}
... process users
for user in users {
dispatch_group_enter(downloadGroup) // 3
UserManager.retrieveFriendsForUser(user, completed: { (usersFriends, fault) in
// No matter the outcome of the call we want to leave the
// dispatch_group so we don't wait forever
defer {
// Balances the enter() for each user
dispatch_group_leave(downloadGroup)
}
.... process userFriends
}
}
推荐阅读:http://commandshift.co.uk/blog/2014/03/19/using-dispatch-groups-to-wait-for-multiple-web-services/