我的Firebase实时数据库的结构如下:

 {
  "friends" : {
    "-LhZw8ryHbE-VIeh1kx6" : {
      "members" : [ "3rTK12GBEQf8WMbLEdAz4Pftkxs1", "guHd7whcqyfFjfkduPoCmryLe0I3" ],
      "title" : "Ansh’s Trials"
    },
    "-LhdBeCVRfDVQBtoAeuf" : {
      "members" : [ "3rTK12GBEQf8WMbLEdAz4Pftkxs1", "guHd7whcqyfFjfkduPoCmryLe0I3" ],
      "title" : "Trial 2"
    },
  },
  "users" : {
    "3rTK12GBEQf8WMbLEdAz4Pftkxs1" : {
      "email" : "anshgodha77@gmail.com",
      "fullname" : "Ansh Godha",
      "provider" : "Firebase"
    },
    "guHd7whcqyfFjfkduPoCmryLe0I3" : {
      "email" : "harvey@davidson.com",
      "fullname" : "Harvey Davidson",
      "provider" : "Firebase"
    }
  }
}

现在,在应用程序中,我创建了用户组,如您所见,每个组都添加在数据库的“朋友”下。我试图在表视图中检索所有组。在这个表视图中,我将组标题设置为“friends”子树中相应组的“title”值。给定组键,设置标题很简单。然而,似乎我在检索组中人员的姓名时遇到了问题。注意,要在我的模型中存储一个组,我将用户的uid存储在该特定组中(请参阅JSON树)。以下是我尝试执行此操作的方法(有关代码的其他信息,请参阅下面的指针):
func getUserFullname(forUID uid: String, handler: @escaping (_  username: String) -> ()) {
        print(5)

            self.REF_USERS.observeSingleEvent(of: .value) { (userSnapshot) in
                print(6)
                guard let userSnapshot = userSnapshot.children.allObjects as? [DataSnapshot] else { return }
                print(7)
                for user in userSnapshot {
                    print(8)
                    if user.key == uid {
                        handler(user.childSnapshot(forPath: "fullname").value as! String)
                    }
                }
            }
    }

func getFullnameList(fromUIDArray uidarr: [String], completion: @escaping (_ nameArr: [String]) -> ()){
    var namearr = [String]()

    print(1)

    for uid in uidarr {
        print(2)
        DataService.instance.getUserFullname(forUID: uid) { (returnedFullName) in
            namearr.append(returnedFullName)
        }
        print(3)
    }

    print(4)
    completion(namearr)

}

REF_用户定义为Database.database().reference().child("users")
DataService是定义了这两种方法的单例。
我知道代码背后的逻辑是正确的,因为当我打印结果时,我可以看到正确的名称。只是在代码的所有其他部分完成执行之后,我看到了名称。实际上,nameArr是一个空数组,即使在第二个方法的末尾。
那么,如何才能使用户名正确传递到nameArr?我试着引用所有其他的SO帖子,它们似乎都是这样使用完成处理程序的。谢谢!
PS:我对Swift和IOS AppDev非常陌生,如果这仍然是一个非常常见的问题,我很抱歉!但是我试着实现我在网上找到的不同的东西(比如DispatchQueues),但是没有成功:(。此外,这是我的第一个StackOverflow帖子之一,所以很抱歉,如果它缺乏细节。将发布更多需要的信息!

最佳答案

我建议换一种结构。阵列在NoSQL数据库中具有固有的挑战性,通常有更好的选择。
假设用户节点

users
   uid_0
      name: "Bill"
   uid_1
      name: "Ted"

以及一个提议的群组结构
groups
   group_0
      name: "My Most Excellent Group"
      members:
         uid_0: true
         uid_1: true

然后一些代码来读取组,打印标题,然后遍历成员列表中的每个子项,从users节点获取成员名称并打印出来。我添加了一些注释,这样您可以更轻松地遵循代码。
func readGroups() {
    let groupsRef = self.ref.child("groups")
    groupsRef.observeSingleEvent(of: .value, with: { snapshot in //read all groups at once
        let allGroupsArray = snapshot.children.allObjects as! [DataSnapshot] //put each child into an array as a DataSnapshot
        for groupSnap in allGroupsArray { //iterate over the array so we can read the group name and group members
            let groupName = groupSnap.childSnapshot(forPath: "title").value as? String ?? "No Group Name"
            print("group: \(groupName) has the following members")
            let members = groupSnap.childSnapshot(forPath: "members") //get the members child as a DataSnapshot
            let allMembers = members.children.allObjects as! [DataSnapshot] //put the members into an array
            for memberSnap in allMembers {
                let memberUid = memberSnap.key //get the uid of each member
                let memberRef = self.ref.child("users").child(memberUid) //get a reference to the member
                memberRef.observeSingleEvent(of: .value, with: { childSnap in //read the member in, print name
                    let name = childSnap.childSnapshot(forPath: "name").value as? String ?? "No Name"
                    print("  name: \(name)")
                })
            }
        }
    })
}

输出将是
group: My Most Excellent Group has the following members
  name: Bill
  name: Ted

10-07 12:04
查看更多