将数据从Firebase拉入阵列

时间:2017-01-19 21:06:28

标签: ios swift firebase firebase-realtime-database

最近我告诉我以不同的方式构建我的Firebase。在我将与特定用户相关的所有内容放在他或她的树下之前。然而,我被告知要将它展平并分别创建他或她的节点,然后在需要时将该节点链接到该用户树。

所以我的树看起来像这样

root
    card
        *card autoID*
            nickname: "foo"
            type: "bar"

    user
        *user uid*
            card
                *card autoID*: true

随着用户在应用程序中前进,我将向卡添加更多内容,如果我理解我应该如何构建数据,我将把它添加到卡节点​​,因为该卡已链接到用户

我的问题是如何从Firebase中提取数据然后说成数组或字典?如果它只在一棵树上我会做这样的事情

let ref = FIRDatabase.database().reference()

let user = FIRAuth.auth()?.currentUser

let userCard = ref.child((user?.uid)!).child("card")

但是,由于用户下的那张卡只是一个参考,我如何去卡片的真实位置...那个有昵称和类型的部分?

修改

所以在其他SO帖子,文档和朋友的帮助下,我有90%的代码工作。

我能做的是

1)找到与用户关联的用户节点下的所有 card autoID 并将这些字符串存储到数组#1

2)我能够查询节点卡下的所有 card autoID ,然后找到与数组#1匹配的那些 card autoID 并将它们存储在数组#2中(其余的都是忽略)

3)**这是我被困的地方。如果我在.observe内部,那么我可以用数组做我想要的事情,比如打印它的内容。但是,如果我在.observe之外打印,我什么也得不到......

这是我的代码

  func pullCurrentUserCardInfo() {

let userCardsRef = ref.child("users").child((user?.uid)!).child("cards")

userCardsRef.observeSingleEvent(of: .value, with: {(snapshot) in

  if let snapDict = snapshot.value as? [String: AnyObject] {
    for each in snapDict {
      self.usersCardRefArray.append(each.key)

      self.count = Int(snapshot.childrenCount)

    }
  }
})

self.ref.child("cards").observe(.value, with: { (snapshot) in
  if snapshot.hasChildren() {

    for item in snapshot.value as! [String: AnyObject] {

      for test in self.usersCardRefArray {

        if test == item.key {
          self.allCurrentUsersCards.append(item.key)
        }
      }
    }
  } else {
    print("no children")
  }

})
}

如果我在函数内部说明以下内容但在.observe ....}之外,那么它什么都不做......

for item in allCurrentUsersCards {
    print(item)
} 

我在某处丢失了一些小东西,还是与firebase有关?

1 个答案:

答案 0 :(得分:2)

我认为这里有一个不必要的复杂程度。您不需要为每个用户存储(在此用例中至少)一张单独的卡。用户和卡之间存在1-1关系,因此只需在用户节点中存储每个用户的卡数据就是最好的答案。

然而,要直接回答这个问题,这里是如何做到的。我们将略微改变Firebase结构:

root
    cards
        *user uid* <- CHANGE
            nickname: "foo"
            type: "bar"

    users
        user uid: true <- CHANGE

由于用户uid始终是唯一的并且是为您创建的,因此在与用户合作时可以利用它们。因此,在这种情况下,只需将用户uid存储在用户节点中,并将相同的uid存储在卡节点中。

创建一个用户类和一个数组来存储它们。这通常在viewController中完成,例如

class ViewController: UIViewController {
  class UserClass {
    var uid = ""
    var nickname = ""
    var type = ""
  }

  var usersArray = [UserClass]()

然后,制作一个Firebase观察者来填充usersArray,为每个用户获取每张卡

//iterate over all of the users, get the user and its card data
let usersRef = ref.child("users") 
usersRef.observeSingleEvent(of: .value, with: { snapshot in

    for snap in snapshot.children { //iterate over all users
        let userSnap = snapshot as! FIRDataSnapshot
        let userKey = userSnap.key //the uid of each user

        //now that we have the uid, get it's card data
        let thisUserCardRef = cardsRef.child("uid")
        thisUserCardRef.observeSingleEvent(of: .value, with: { userSnap in
          let userCardSnap = userSnap as! FIRDataSnapshot
          let userCardDict = userCardSnap.value as! [String:AnyObject]
          let nickname = userCardDict["nickname"]
          let type = userCardDict["type"]

          let aUser = UserClass()
          aUser.userKey = userKey
          aUser.nickname = nickname
          aUser.type = type

          self.usersArray.append(aUser)

          //In general, this is where the tableView is refreshed
          // because the user data and card data is valid at this point
          //usersTableView.reload data /
        })
    }
})

这里的关键是要记住Firebase是异步的,而且代码比互联网快。所以这个高级示例大部分时间失败

func getData() {
   loadDataFromFirebase()
   print("data loaded, do something with it") //<- executes before the prior line completes
}

func loadDataFromFirebase() {
  someRef.observeEvent...
     print("data is now valid inside observe closure")
}

这通常会导致

data loaded, do something with it
data is now valid inside observe closure

与想要的相反。代码执行速度比Internet快,因此在打印数据加载后,将发生异步观察闭包。仅在闭包内引用和处理firebase数据,并使用闭包来调整应用程序。

如果您在提供的第一个示例代码中注意到 - 我们只会在从Firebase返回数据后使用这些数据。

另请注意,我们完全取消了查询!与观察事件相比,查询“很重”,因为我们正在利用每个用户的uid,它的路径将是已知的,因此从使用childByAutoId创建的节点更改为使用uid。