【问题标题】:Append to array inside a Firebase Closure in Swift 3在 Swift 3 中附加到 Firebase 闭包内的数组
【发布时间】:2017-07-18 02:24:05
【问题描述】:

我正在尝试附加到 Firebase 闭包内的数组, 我在闭包之外声明了数组var CanJoinArray = [String]() 但是当我尝试附加到闭包内的数组时:self.CanJoinArray.append("hello") 并在闭包之外打印它,print (CanJoinArray) 它不会打印。但是,当我在(内部)闭包内打印数组时,它可以追加和打印。我该如何解决这个问题?谢谢!

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

数据库结构:

{
 "Lobbies" : {
    "RANDOMUUID" : {
       "LobbyName" : {
          "LobbyName" : ""
       },
       "Players" : {
          "user1" : "USERUID#"
       }
    }
 },
 "Users" : {
    "USERUID#" : {
      "DisplayName" : "user1"
    }
  }
}

【问题讨论】:

  • 你的意思是'if'语句吗?不确定“in”语句是什么。
  • 是的对不起...我的意思是一个 if 语句
  • 请发布一个简短的代码示例来显示问题
  • @simonWasHere 刚刚做到了。
  • myArray 和 CanJoinArray 有什么联系?

标签: ios swift firebase firebase-realtime-database


【解决方案1】:

你可以去几个方向......

您似乎想要维护可用大厅的列表,而可用性取决于大厅中的玩家数量。在这种情况下,0 或 1 名玩家意味着它可用,如果 2 或更多意味着它已满。

想到的第一个选项是通过在大厅中添加 is_available 节点来更改您的结构。当玩家加入该大厅时,将其 uid 添加到玩家子级,如果是第二个玩家,则将 is_available 更新为 false。结构看起来像这样:

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

代码将是一个查询:

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

这会将 lobby_id_1 添加到数组中,因为其他两个大厅各有两名玩家。

第二种解决方案是保留列出可用大厅的第二个节点。

这里是 All_Lobbies 节点和 Available_Lobbies 节点

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

类似的概念;当一个玩家加入 lobby_id_1 并且是两个玩家(所以它已满)时,只需从 Available_Lobbies 节点中移除该大厅。

查看哪些代码可用:

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

这种结构的优点是双重的。我们完全消除了查询,因为只有可用的大厅存储在该节点中。查询比观察“重”得多,并且占用更多资源。第二件事是,如果有 100 万个 Available_Lobbies,我们加载的数据就会少得多!

【讨论】:

  • 一切正常,唯一的小问题是:我收到此警告Using an unspecified index. Consider adding ".indexOn": "is_available" at /Lobbies to your security rules for better performance
  • @adameliezerov 为您的数据编制索引可以显着提高查询性能 - 但您必须提前计划您将使用哪种查询。阅读Index Your Data 以获得一些非常好的示例和用例。如果您只是在测试或开始使用,您可以忽略该消息,但是当您开始使用该应用程序或使用更大的数据集时,它变得更加重要。
  • 好的。另一个问题:每当我创建一个新大厅时,我也会这样做:self.ref.child("Available_Lobbies").setValue([self.uuid: true]) 但是,每次我创建一个新大厅时,它都会重写旧大厅。
  • @adameliezerov 对。它正在做你告诉它做的事情:写入节点 rootref/Available_Lobbies/uid: true。所以这段代码不是创建一个新的大厅,而是写一个特定的大厅。如果您想创建新的大厅,您应该使用 .childByAutoId 来创建大厅键(我的回答中的大厅_0、大厅_1 等)。 .childByAutoId 在调用时会生成一个唯一键,非常适合节点键。如果您仍然遇到问题,这确实是一个单独的问题。这里有 很多 参考资料和示例。
  • 那我怎么得到那个autoId呢?
【解决方案2】:

也许只是将打印语句上移一个,

 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

})

【讨论】:

  • 不起作用。它仍然没有显示任何东西被添加到数组中
  • 如何将它移到原始代码下方的完成之外?
  • 如果我这样做是空的。
  • 你在正确的轨道上。将print(CanJoinArray) 语句移动到回调中(再向上两行),它就会起作用。
  • @FrankvanPuffelen 它打印 CanJoinArray 我在 MyArray 中有元素的次数
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-16
  • 1970-01-01
  • 2016-11-20
  • 1970-01-01
  • 2015-06-14
相关资源
最近更新 更多