问题
I am trying to append to an array inside a Firebase closure,
I declared the array outside of the closure var CanJoinArray = [String]() But when I try to append to the array inside the closure: self.CanJoinArray.append("hello") and print it outside of the closure, print (CanJoinArray) it doesn't print. However, when I print the array inside the (inside) closure, it is able to append and print. How can I solve this? Thanks!
ref.observeSingleEvent(of: .value, with: { (FIRDataSnap) in
for child in FIRDataSnap.children.allObjects {
let key = (child as AnyObject).key as String
self.myArray.append(key)
}
for (_, element) in self.myArray.enumerated() {
self.ref.child(element).child("Players").observeSingleEvent(of: .value, with: { (Snap) in
if Snap.childrenCount < 2 {
self.CanJoinArray.append("hello")
}
else {
print("Can't join lobby\(element)... Full!")
}
print(CanJoinArray) //this does work
})
}
print (CanJoinArray) //this doesn't work
})
}
The database Structure:
{
"Lobbies" : {
"RANDOMUUID" : {
"LobbyName" : {
"LobbyName" : ""
},
"Players" : {
"user1" : "USERUID#"
}
}
},
"Users" : {
"USERUID#" : {
"DisplayName" : "user1"
}
}
}
回答1:
There are a couple of directions you can go...
It appears that you want to maintain a list of lobbies that are available, and the availability is determined by the number of players in the lobby. In this case 0 or 1 players means it's available and if 2 or more means it's full.
The first option that comes to mind is to change your structure by adding a is_available node within the lobby. When a player joins that lobby, add their uid to the players child and update the is_available to false if it's the second player. The structure would look something like this:
Lobbies
lobby_id_0
lobby_name: "lobby 5"
is_available: false
players
uid_0: true
uid_1: true
lobby_id_1
lobby_name: "lobby 12"
is_available: true
players
uid_2: true
lobby_id_2
lobby_name: "some lobby"
is_available: false
players
uid_3: true
uid_4: true
The code would be a query:
let lobbiesRef = rootRef.child("Lobbies")
let queryRef = lobbiesRef.queryOrdered(byChild: "is_available").queryEqual(toValue: true)
queryRef.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! FIRDataSnapshot
let lobbyDict = snap.value as! [String: Any]
let lobbyKey = snap.key
self.availableLobbyArray.append(lobbyKey)
}
})
This would add lobby_id_1 to the array as the other two lobbies each have two players.
A second solution is to keep second node that lists lobbies that are available.
Here's the All_Lobbies node and the Available_Lobbies node
All_Lobbies
lobby_id_0
lobby_name: "lobby 5"
players
uid_0: true
uid_1: true
lobby_id_1
lobby_name: "lobby 12"
players
uid_2: true
Available_Lobbies
lobby_id_1: true
Kind of the same concept; when a player joins lobby_id_1 and it's two players (so it's full), simply remove that lobby from the Available_Lobbies node.
The code to see which are available:
let availableLobbiesRef = rootRef.child("Available_Lobbies")
availableLobbiesRef.observeSingleEvent(of: .value, with: { (snapshot) in
for child in snapshot.children {
let snap = child as! FIRDataSnapshot
let lobbyKey = snap.key
self.availableLobbyArray.append(lobbyKey)
}
})
The advantage of this structure is two-fold. We eliminate the query completely because only available lobbies are stored in that node. Queries are much 'heavier' than an observe and take more resources. The second thing is that if there are 1 Million Available_Lobbies, we are loading in far less data!
回答2:
Just move the print statement up one maybe,
for (_, element) in self.myArray.enumerated() {
self.ref.child(element).child("Players").observeSingleEvent(of: .value, with: { (Snap) in
if Snap.childrenCount < 2 {
self.CanJoinArray.append("hello")
}
else {
print("Can't join lobby\(element)... Full!")
}
})
print (CanJoinArray)
}
you were here
})
来源:https://stackoverflow.com/questions/42486321/append-to-array-inside-a-firebase-closure-in-swift-3