Pulling Data From Firebase Issue

后端 未结 3 1190
孤街浪徒
孤街浪徒 2021-01-25 00:51

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

3条回答
  •  暗喜
    暗喜 (楼主)
    2021-01-25 01:42

    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.

提交回复
热议问题