如何调用合并多个完成处理程序以将数据合并到一个新数组

时间:2019-06-15 01:44:54

标签: swift firebase firebase-realtime-database

我已经被困了一段时间,任何建议将不胜感激。我正在创建一个使用Firebase数据库的应用程序,并且创建了5个类,这些类在Firebase中保存不同的数据。我正在创建一个需要显示5个类中的每个类的信息的表视图(配置文件名称,图像,然后是有关联赛的信息以及有关得分的信息)。因此,在新的类中,我创建了一个函数,该函数从每个类的firebase中调用数据。 例如:获取X联赛{     对于联盟中的每个球员{         获取玩家信息         然后获取分数         然后不停地         一旦我们拥有所有信息,追加到新数组 }      然后对数组进行排名 }

所有这些运行之后,我想在VC上重新加载表视图

因此,我的解决方案适用于原始负载,但是如果我退出并重新进入屏幕,则名称和图像会重复。

确切地说,当索引打印到控制台时,我得到了 “玩家1:扎克” “玩家2:约翰” 但是,屏幕上反复显示John的图像和姓名。但是,只有该类……所有其他数据都保留在应有的位置。原始函数都以相同的方式编写。

我认为这与内存管理有关,还是写得不好我的完成处理程序?

这是新数组类中的代码:

您还会注意到,我的complete()位于我讨厌的for循环中,但这是我可以在完成之前完成该功能的唯一方法。否则,该功能会在数据准备就绪之前完成。

func getLeaderboard(leagueID: String, completion: @escaping ()->()) {

        print("League Count After removeAll \(self.rankedGolfers.count)")
        self.leagueMembers.getLeagueMembers(leagueID: leagueID) {
            print("HANDLER: Step 1: Get League Members")

            for member in self.leagueMembers.leagueMembers {

                print("Golfer Member ID: \(member.userID)")
                self.golferInfo.getGolferInfo(userKey: member.userID, completion: {
                    print("HANDLER: Step 2: Get player profile info")
                    print("Golfer Name3: \(self.golferInfo.golfers[0].firstName) \(self.golferInfo.golfers[0].lastName)")
                    self.handicapHelper.getRounds(userID: member.userID, completion: {
                        print("HANDLER: Step 3: Get players Handicap")
                        print("Golfer Handicap3: \(self.golferInfo.golfers[0].lastName): \(self.handicapHelper.handicap)")

                        self.leagueInfo.getLeagueInfo(leagueID: leagueID, completion: {
                            print("HANDLER: Step 4: Get league info")
                            let golferIndex = self.golferInfo.golfers[0]
                            let memberInfoIndex = self.leagueInfo.leagueInfo[0]
                            let golferID = member.userID
                            let profileImg = golferIndex.profileImage
                            let golferName = "\(golferIndex.firstName) \(golferIndex.lastName)"
                            let handicap = self.handicapHelper.handicap
                            let golferLeaguePardieScore = member.pardieScore
                            let leagueRoundsPlayed = member.numberOfRounds
                            let roundsRemaining = memberInfoIndex.leagueMinRounds - leagueRoundsPlayed
                            let currentWinnings = member.currentWinnings

                            let newGolfer = Leaderboard(golferID: golferID, profileImg: profileImg ?? "No Img", golferName: golferName, golferHandicap: handicap, golferLeaguePardieScore: golferLeaguePardieScore, roundsPlayedInLeague: leagueRoundsPlayed, roundsRemaining: roundsRemaining, currentWinnings: currentWinnings)

                            self.rankedGolfers.append(newGolfer)

                            print("HANDLER: Step 5: Add golfer to array")
                            //print("Golfer Name 4: \(newGolfer.golferName)")
                            //print("Rounds Remaining: \(newGolfer.roundsRemaining)")
                            print("league Member Count: \(self.rankedGolfers.count)")
                            self.getLeaderboardRanking()
                            print("HANDLER: Step 6: Rank Array")
                            //print("COMPLETION: \(self.rankedGolfers.count)")
                            completion()
                        })
                    })

                })
            }
        }

}

谢谢您的帮助!

1 个答案:

答案 0 :(得分:0)

我认为我们可以使用DispatchGroup解决此问题,这将确保为每个用户加载所有数据,然后将用户添加到用作tableView dataSource的数组中,然后在完成后重新加载tableView。

为简单起见,我们将从UserInfo类开始,该类存储其uid,名称,喜欢的食物和障碍。

class UserInfoClass {
    var uid = ""
    var name = ""
    var favFood = ""
    var handicap = 0
}

和用作tableView的数据源的类var数组

var userInfoArray = [UserInfoClass]()

然后,假设我们具有这样的结构...

users
   uid_0
      name: "Leroy"

handicaps
   uid_0
      amt: 4

fav_foods
   uid_0
      fav_food: "Pizza"

...这是一个读取所有用户的函数,然后遍历每个用户,并使用其名称和uid填充UserInfoClass,并创建一个调度组,该调度组也填充其最喜欢的食物和障碍。完成此操作后,会将用户添加到dataSource数组中,并且在读取所有用户后,将重新加载tableView以显示信息。

func loadUsersInfoAndHandicap() {
    let ref = self.ref.child("users")
    self.userInfoArray = []
    ref.observeSingleEvent(of: .value, with: { snapshot in
        let group = DispatchGroup()
        let allUsers = snapshot.children.allObjects as! [DataSnapshot]
        for user in allUsers {
            let uid = user.key
            let name = user.childSnapshot(forPath: "name").value as? String ?? "No Name"

            let aUser = UserInfoClass()
            aUser.uid = uid
            aUser.name = name

            group.enter()
            self.loadFavFood(withUid: uid) {favFood in
                aUser.favFood = favFood
                group.leave()
            }

            group.enter()
            self.loadHandicap(withUid: uid) { handicap in
                aUser.handicap = handicap
                group.leave()
            }

            group.notify(queue: .main) {
                self.userInfoArray.append(aUser)
            }
        }

        group.notify(queue: .main) {
            print("done, reload the tableview")
            for user in self.userInfoArray {
                print(user.uid, user.name, user.favFood, user.handicap)
            }
        }
    })
}

从主要用户节点读取用户名和uid,这是读取他们最喜欢的食物和障碍的两个函数。

func loadFavFood(withUid: String, completion: @escaping(String) -> Void) {
    let thisUser = self.ref.child("userInfo").child(withUid)
    thisUser.observeSingleEvent(of: .value, with: { snapshot in
        let food = snapshot.childSnapshot(forPath: "fav_food").value as? String ?? "No Fav Food"
        completion(food)
    })
}

func loadHandicap(withUid: String, completion: @escaping(Int) -> Void) {
    let thisUser = self.ref.child("handicaps").child(withUid)
    thisUser.observeSingleEvent(of: .value, with: { snapshot in
        let handicap = snapshot.childSnapshot(forPath: "amt").value as? Int ?? 0
        completion(handicap)
    })
}

请注意,self.ref指向我的firebase,因此请替换为您的 firebase的引用。

请注意,我输入的内容非常快,基本上没有错误检查,因此请相应添加。