情况是我需要遍历多个对象并在每个对象上进行网络调用。
在完成所有网络呼叫后,我将使用从这些网络呼叫中收集的所有数据来调用我的完成块。
为了做到这一点,我试图使用一个调度组,在网络呼叫开始时进入,在完成时离开:
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);
但是,它似乎不等待我的所有分组网络呼叫完成。
以下是完整上下文中的所有代码;我正在循环遍历许多用户,然后查询他们的朋友。我希望该方法能够将所有朋友组合在一起(通过将所有结果连接到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)
}
答案 0 :(得分:2)
每次拨打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
您没有平衡第一次检索当前用户的朋友。
如果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/