调度队列不等待

时间:2016-04-11 22:25:50

标签: ios grand-central-dispatch

情况是我需要遍历多个对象并在每个对象上进行网络调用。

在完成所有网络呼叫后,我将使用从这些网络呼叫中收集的所有数据来调用我的完成块。

为了做到这一点,我试图使用一个调度组,在网络呼叫开始时进入,在完成时离开:

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

1 个答案:

答案 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

问题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/