将两个单独的Firebase节点中的数据加载到一个表格视图单元格中

问题描述 投票:0回答:2

我是Swift 3和Firebase的新手,因此在从两个不同节点检索数据并将其显示在一个表格视图单元格中存在一些问题。我在Stack Overflow上找到了一些类似的问题,如下所示:

Firebase - iOS Swift: load table view cell with data retrieved from two separate child nodes

但无法将其应用于我的代码,因为这些示例对于提问者来说过于具体,或者我对Firebase缺乏了解,导致我无法继续提供所提供的答案。

我的应用程序是使用Xcode-8在Swift 3中编写的,并使用Firebase进行数据持久化。该应用程序的目的是允许用户提交不同的锻炼计划以供其他用户使用。用户提交的程序具有与之关联的作者的uid,我计划使用它来根据此uid值从单独的节点检索用户的用户名。

我的Firebase设置:

    "programs" : {
    "-KYF3o3YD6F3FEXutuYH" : {
      "content" : "Program Content Goes Here...",
      "duration" : "4 Weeks",
      "title" : "Chest Blast",
      "type" : "Hypertrophy",
      "uid" : "oLy9GOzDyKht7WWVZgpd3jPHxsE3"
    },
    "-KYF4ev88FQ2nEr6yTOW" : {
      "content" : "Program Content Goes Here...",
      "duration" : "6 Weeks",
      "title" : "Full Back Workout",
      "type" : "Strength",
      "uid" : "oLy9GOzDyKht7WWVZgpd3jPHxsE3"
    },
    "-KZRYF9A8-8OHCNzOoPT" : {
      "content" : "Eugene and Eamon",
      "duration" : "4 Weeks",
      "title" : "abc",
      "type" : "abc",
      "uid" : "oLy9GOzDyKht7WWVZgpd3jPHxsE3"
    },
    "-KbKNdrAcBarpaNoGf_e" : {
      "content" : "Test",
      "duration" : "test",
      "title" : "New Test",
      "type" : "test",
      "uid" : "oLy9GOzDyKht7WWVZgpd3jPHxsE3"
    },
    "-KbKnXnyzj_EJp_wNw5y" : {
      "content" : "1. Barbell Bench Press\n\nWhy it's on the list: You can generate the most power with barbell lifts, so the standard barbell bench allows you to move the most weight. It's also an easier lift to control than pressing with heavy dumbbells. The exercise is easy to spot and relatively easy to learn (if not master), There are plenty of bench-press programs you can follow to increase your strength.\n\n1. Barbell Bench Press\n\nWhy it's on the list: You can generate the most power with barbell lifts, so the standard barbell bench allows you to move the most weight. It's also an easier lift to control than pressing with heavy dumbbells. The exercise is easy to spot and relatively easy to learn (if not master), There are plenty of bench-press programs you can follow to increase your strength.",
      "duration" : "1",
      "title" : "1",
      "type" : "1",
      "uid" : "oLy9GOzDyKht7WWVZgpd3jPHxsE3"
    }
  },
  "users" : {
    "hds1WketiAUELVDOz1Dprvlu0KE3" : {
      "username" : "Example"
    },
    "oLy9GOzDyKht7WWVZgpd3jPHxsE3" : {
      "username" : "Test"
    }
  }

应用程序中的表格如下所示:

Table View

正如你所看到的,目前作者只是被他们的uid所指示。这很容易,因为我将它存储在与显示的所有其他数据相同的位置但我需要使用该uid值来搜索另一个节点并获取与其关联的用户名并将其显示在现在显示uid的位置。

下面是我用来检索和显示数据的代码。我的主要问题是:

1:我可以使用什么查询来搜索用户节点以查找匹配的uid,只获取该人的用户名并将其显示在表格视图中?

2:我应该在代码中放置该查询?我只是想把它放在func tableView()方法中,因为我可以在每次将新帖子添加到单元格时搜索用户,这样我就不必再制作另一个NSMutable数组来保存用户甚至没有帖子。非常感谢您提供的任何帮助。

@IBOutlet weak var programsTableView: UITableView!
var programs = NSMutableArray()

override func viewDidLoad() {
    super.viewDidLoad()

    self.programsTableView.delegate = self
    self.programsTableView.dataSource = self

    //Call load data method to populate table with data from Firebase
    loadData()
}

//Method to load data from Firebase
func loadData(){

FIRDatabase.database().reference().child("programs").observeSingleEvent(of: .value, with: { (snapshot) in
        //Snapshot holds value and it is casted to NS Dictionary
        if let programsDictionary = snapshot.value as? [String: AnyObject]{
            for program in programsDictionary{
                self.programs.add(program.value)
            }
            self.programsTableView.reloadData()
        }
    })
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! AllProgramsTableViewCell

    // Configure the cell...
    let program = self.programs[indexPath.row] as! [String: AnyObject]

    //Populate row
    //Grab title and add it to cell
    cell.titleLabel.text = program["title"] as? String
    //Grab type and add it to cell
    cell.typeLabel.text = program["type"] as? String
    //Grab duration and add it to cell
    cell.durationLabel.text = program["duration"] as? String
    //Grab content and add it to cell
    cell.contentTextView.text = program["content"] as? String
    //Grab author and add it to cell
    cell.authorLabel.text = program["uid"] as? String

    return cell
}
ios swift firebase swift3 tableview
2个回答
2
投票

一些事情可以帮助你。

1:我可以使用什么查询来搜索用户节点以查找匹配的uid,只获取该人的用户名并将其显示在表格视图中?

首先,更改用户节点并将uid用作每个用户的密钥

users
  uid_0
    name: "Hans"
    userName: "pump_u_up"
  uid_1
    name: "Franz"
    userName: "abs_of_steel"

这避免了必须查询。查询比观察“更重”并占用更多资源。通过使用uid,您可以直接捕获用户信息。例如:

let userRef = rootRef.child("uid from programs node")
userRef.observeSingleEvent(of: .value, with: { snapshot in
    let userDict = snapshot.value as! [String:AnyObject]
    let userName = userDict["userName"] as! String
    print(userName)
})

2:我应该在代码中放置该查询?我只是想把它放在func tableView()方法中,因为我可以在每次将新帖子添加到单元格时搜索用户,这样我就不必再制作另一个NSMutable数组来保存用户甚至没有帖子。非常感谢您提供的任何帮助。

既然您已经拥有了捕获用户信息的代码,那么添加它就很容易,但是,我建议采用与发布的方法略有不同的方法。

从ProgramClass开始

class ProgramClass {
    var key = ""
    var content = ""
    var duration = ""
    var username = ""
}

并因此填充数据源:

ref.child("programs").observeSingleEvent(of: .value, with: { (snapshot) in
     for snap in snapshot.children {
          let programSnap = snap as! FIRDataSnapshot
          let programKey = programSnap.key //the key of each program
          let programDict = programSnap.value as! [String:AnyObject] //program child data
          var aProgram = ProgramClass()
          aProgram.key = programKey
          aProgram.content = programDict["content"] as! String
          //etc
          let uid = programDict["uid"] as! String
          let userRef = ref.child("users").child(uid)
          userRef.observeSingleEvent(of: .value, with: { snapshot in
             let userDict = snapshot.value as! [String:AnyObject]
             let userName = userDict["userName"] as! String
             aProgram.username = userName
             self.programsArray.append[aProgram]
        })
    }
}

上面的代码可能会大大缩短,但为了便于阅读,它会更加冗长。

哦,不要忘记以Swifty方式定义数据源数组:

var programsArray = [ProgramClass]()

-1
投票

更新:getUserName没有那样工作,因为observeSingleEvent是一个asyc电话。 (感谢@Aodh)

PS:我不知道是否最好删除答案或将其作为一个坏例子?


解决方案只是再次检索用户数据:

您应该更改您的架构,而不是在程序中保存uid而是userId

"programs":
     "programId1234":
         [...]
         "userId": "userid12345
"users":
     "userId1234":
         "uid": "uidxxxxxx"
         "username" : "jim"

码:

FIRDatabase.database().reference().child("programs").observeSingleEvent(of: .value, with: { (snapshot) in
        //Snapshot holds value and it is casted to NS Dictionary

        //change to var!
        if var programsDictionary = snapshot.value as? [String: AnyObject]{
            for program in programsDictionary{
                // add there
                let programDictionary = program.value as? [String: AnyObject]
                let authorUid = programDictionary["userId"] as? String
                let authorName = getUserName(forUid: authorUid)
                programDictionary["authorname"] = autorName
                //
                self.programs.add(programDictionary)
            }
            self.programsTableView.reloadData()
        }
    })


func getUserName(forUid userID: String) -> String {
    var userName = nil
    FIRDatabase.database().reference().child("users").child(userID)
         .observeSingleEvent(of: .value, with: { (snapshot) in
              if let userDictionary = snapshot.value as? [String: AnyObject]{
                  userName = userDictionary["username"] as? String
              }
        })
    return userName

}

以后不再需要转换它 - 你可以改变这一行:

// Configure the cell...
let program = self.programs[indexPath.row] as! [String: AnyObject]

// Configure the cell...
let program = self.programs[indexPath.row]

这是join调用的一个例子:https://firebase.googleblog.com/2013/10/queries-part-1-common-sql-queries.html#join

© www.soinside.com 2019 - 2024. All rights reserved.