Novice programmer, currently working on an ios app using firebase as our backend. I\'m trying to grab values from the firebase database to populate a TableView, but there are tw
In general: It's best practise to create a function for your download purposes and call the function instead of putting all the lines of code inside your cell declaration:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "committeeCell", for: indexPath) as! CommitteeTableViewCell
// we are passing the Label and the indexPath to out func
myFirebaseFunc(label: cell.committeeLabel, indexPath: indexPath)
return cell
}
Also you should use observeEventType, to handle the case, that there might be data added to your Firebase during runtime and you want the data to be added to your UITableView.
func myFirebaseFunc(label: UILabel, indexPath: NSIndexPath) {
let sectionRef = FIRDatabase.database().reference(withPath: "Committee".child(String(indexPath.section))
let committeeRef = sectionRef.child(String(indexPath.row))
let currentRef = committeeRef.child(String(indexPath.row)).child("name")
currentRef.observeEventType(of: .value, withBlock: { (snapshot) in
if snapshot.exists() {
label?.text = snapshot.value as? String
}
})
}
To your case: Also I assume that your App crashes because indexPath out of bounds. It's not best practise to download your Firebase data according to your indexPath within the population of the Cell. Since, as stated correctly by Jay, the download is async.
You have to download your desired data first and then populate a tableView according to your data like this:
You create an Array of Models (struct) or NSMutableDictionary.
// first you check, if your snapshot exists
if snapshot.exists() {
// you delete your Array, you your data will not be added multiple
// times once you add data in the background and the func gets
// called again
self.myArray.removeAll()
// you sort your snapshot according to your needs (for example of the (pre set) date value. If date is missing, the code will not crash!
let sorted = (snapshot.value!.allValues as NSArray).sortedArrayUsingDescriptors([NSSortDescriptor(key: "date",ascending: false)])
// then you loop through your sorted Array
for element in sorted {
// you create a name String of your name element in your Dictionary
let name = element.valueForKey("name")! as? String
// if you have created a struct, you instantiate a model and set the name
let m = MyStruct(name: name!)
// and you append it to your Array
self.myArray.append(m)
}
// last but not least we reload our tableView on the main threat
DispatchQueue.main.async{
self.tableView.reloadData()
}
}
Then you set numbersOfRowsInSection to myArray.count
And fill your tableView with:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "committeeCell", for: indexPath) as! CommitteeTableViewCell
let mine = myArray[indexPath.row]
cell.committeeLabel.text = mine.name
return cell
}
This would be our struct in this example:
struct MyStuct {
var name: String = ""
}
Our Array instantiated in the ViewController class:
let myArray: [MyStruct] = []
In this best practise scenario we would call our myFirebaseFunc func at the viewDidAppear func of our ViewController.