Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/19.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 将数据从两个独立的Firebase节点加载到一个表视图单元中_Ios_Swift_Firebase_Swift3_Tableview - Fatal编程技术网

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

Ios 将数据从两个独立的Firebase节点加载到一个表视图单元中,ios,swift,firebase,swift3,tableview,Ios,Swift,Firebase,Swift3,Tableview,我是Swift 3和Firebase的新手,所以在从两个不同的节点检索数据并在一个表视图单元格中显示数据时遇到了一些问题。我还发现了一些关于堆栈溢出的类似问题,如下所示: 但无法将其应用到我的代码中,因为这些示例对于提问的人来说太过具体,或者我对Firebase的了解不足,导致我无法继续提供答案 我的应用程序是用Swift 3编写的,使用Xcode-8并使用Firebase进行数据持久化。该应用程序的目的是允许用户提交不同的锻炼计划供其他用户使用。用户提交的程序具有与之关联的作者uid,我计划

我是Swift 3和Firebase的新手,所以在从两个不同的节点检索数据并在一个表视图单元格中显示数据时遇到了一些问题。我还发现了一些关于堆栈溢出的类似问题,如下所示:

但无法将其应用到我的代码中,因为这些示例对于提问的人来说太过具体,或者我对Firebase的了解不足,导致我无法继续提供答案

我的应用程序是用Swift 3编写的,使用Xcode-8并使用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"
    }
  }
应用程序中的表如下所示:

正如您所看到的,目前作者只是通过他们的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
}

更新:
getUserName
不是那样工作的,因为
observeSingleEvent
是一个asyc调用。(感谢@Aodh)

附言:我不知道是删除答案更好,还是留下一个坏例子


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

您应该更改您的模式,不在程序中保存uid,而是保存用户ID

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

以后不需要再转换它-您可以更改此行:

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

以下是
join
调用的示例:

更新:
getUserName
不是那样工作的,因为
observeSingleEvent
是一个异步调用。(感谢@Aodh)

附言:我不知道是删除答案更好,还是留下一个坏例子


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

您应该更改您的模式,不在程序中保存uid,而是保存用户ID

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

以后不需要再转换它-您可以更改此行:

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

以下是
join
调用的示例:
有几件事可以帮你解决

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数组来容纳可能 甚至没有帖子。非常感谢您提供的任何帮助

@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
}
现在您已经有了捕获用户信息的代码,添加它只是一个简单的过程,但是,我建议使用一种与发布的方法稍有不同的方法

从编程类开始

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]
        })
    }
}
上面的代码可以大大缩短,但为了便于阅读,会更加冗长

哦,别忘了快速定义数据源阵列:

var programsArray = [ProgramClass]()

有几件事可以帮你

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数组来容纳可能 甚至没有帖子。非常感谢您提供的任何帮助

@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
}
现在您已经有了捕获用户信息的代码,添加它只是一个简单的过程,但是,我建议使用一种与发布的方法稍有不同的方法

从编程类开始

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]
        })
    }
}
上面的代码可以大大缩短,但为了便于阅读,会更加冗长

哦,别忘了快速定义数据源阵列:

var programsArray = [ProgramClass]()

请删除Firebase结构的图像,并以文本形式发布实际Firebase结构,请不要使用图像。这可以从Firebase控制台->右侧三点->导出JSON中获得。使用文本是很重要的,因为它是可搜索的,并且有助于我们帮助您,因为我们不必在答案中重新键入它。@Jay我做了这些更改。抱歉。请删除Firebase结构的图像,并将实际的Firebase结构作为文本发布,请不要使用图像。这可以从Firebase控制台->右侧三点->导出JSON中获得。这是不礼貌的