如何调用合并多个完成处理程序以将数据合并到一个新数组 [英] How to call combine multiple completion handlers to combine data to one new array

查看:41
本文介绍了如何调用合并多个完成处理程序以将数据合并到一个新数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have been stuck for a while now and any advice would be greatly appreciated. I am creating an app that uses Firebase database and I have created 5 classes that hold different data in Firebase. I'm creating a tableview that needs to display information from each of the 5 classes (Profile name, image, then information about a league, and info about scores). So in my new class I created a function calling for data from firebase from each class... For example: GET all players from X league { FOR every player in the league { GET the players information THEN GET the scores THEN on and on once we have all information APPEND to new array } and then rank the array }

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

After all this runs I want to reload the table view on the VC

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

SO my solution works on the original load but if I back out and re enter the screen the names and images repeat.

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

To be exact when the indexes print to the console I get "Player 1: Zack" "Player 2: John" However, the screen shows John's image and name repeatedly. BUT only that class... All other data stays where it is supposed to be. And the original functions are all written the same way.

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

I'm thinking it's something to do with memory management or I wrote my completion handler poorly?

这是新数组类中的代码:

Here is the code in the new array class:

您还将注意到,我的complete()处于我讨厌的for循环内,但这是使函数在完成之前完成的唯一方法.否则,函数在数据准备就绪之前就完成了.

You'll also notice that my completion() is inside my for in loop which I HATE but it's the only way I could get the function to finish before completing.. Otherwise the function completes before the data is ready.

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

                })
            }
        }

}

谢谢您的帮助!

推荐答案

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

I think we can solve this with a DispatchGroup, which will ensure all of the data is loaded for each user, then append the user to an array used as a tableView dataSource and then reload the tableView upon completion.

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

To keep it simple we'll start with a UserInfo class which stores their uid, name, favorite food and handicap.

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

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

and a class var array used as the dataSource for the tableView

var userInfoArray = [UserInfoClass]()

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

Then, assuming we have a structure like this...

users
   uid_0
      name: "Leroy"

handicaps
   uid_0
      amt: 4

fav_foods
   uid_0
      fav_food: "Pizza"

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

...here's a function that reads all users, then iterates over each one populating a UserInfoClass with their name and uid, as well as creating a dispatch group that also populates their favorite food and handicap. When that's complete the user is added to the dataSource array and when all of the users are read the tableView is reloaded to display the information.

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,这是读取他们最喜欢的食物和障碍的两个函数.

the users name and uid is read from the main users node and here are the two functions that read their favorite food and handicap.

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的引用.

note that self.ref points to my firebase so substitute a reference to your firebase.

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

Note I typed this up very quickly and there is essentially no error checking so please add that accordingly.

这篇关于如何调用合并多个完成处理程序以将数据合并到一个新数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆