skip to Main Content

i want to get data from firebase firestore and put that into a tableview in a new view
but when tableview is getting data it’s nil and i got unwrapping error like this picturescreenshot of unwrapping error

this is my tableview code :

class ParcelViewController:UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    let tableCell = ParcelTableViewCell()
    var parcelDataModel = MainViewModel()
    
    @IBOutlet weak var parcelTable: UITableView!
    
    override func viewDidLoad() {
        
       self.parcelDataModel.vc = self
        view.backgroundColor = .white
        parcelDataModel.getCollectionData()
        print("Hi")
    }
    
    var selectionDelegate : ParcelSelectionDelegate!
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        if parcelDataModel.parcels.count > 0 {
            return self.parcelDataModel.parcels.count
        } else {
            return 0
        }
    }
        
        
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            let cell = parcelTable.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! ParcelTableViewCell
            let current = self.parcelDataModel.parcels[indexPath.row]
            cell.parcelTitleLabel.text = current.parcel_type
            cell.parcelImage.image = UIImage(named: current.parcel_img_url)
            cell.parcelWeightlabel.text = "(current.parcel_min_weight)  -  (current.parcel_max_weight)"
            cell.parcelDescriptionLabel.text = current.parcel_description
            return cell
            
        }
        
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            let selected = self.parcelDataModel.parcels[indexPath.row]
            selectionDelegate.parcelDidSelect(parcelType: selected.parcel_type)
        }
    }
    
    

and i want to this code self.parcelDataModel.vc = self comes before viewdidload

i’ve tried it in loadView but it didn’t worked.

2

Answers


  1. Chosen as BEST ANSWER

    i just had to change my if statement in numberOfRowsInSection like below

    if parcelDataModel.parcels != nil {
            return parcelDataModel.parcels.count
            } else {
            return 0
        }
    

    and it works now.


  2. As mentioned in the comments, aiming for an earlier lifecycle access point than viewDidLoad() isn’t likely to help in this situation: it’s almost certain that the view controller lifecycle will complete before a Firebase request will be returned.

    Considering that, modification to the view controller load UX is the answer. There are two main approaches here:

    1. Have a "not loaded/loading" UX in the new view controller, make your Firebase request there, and update your UI when Firebase returns its response.
    2. Make the Firebase request in the preceding view controller, and then load your new view controller with any returned data (assuming that request doesn’t return an error).

    Option 1 might look like:

    class NewViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
        var model: DataModel?   // Must be optional because we'll load initially with it nil
    
        override func viewDidAppear() {
            super.viewDidAppear()
            
            // Show loading UI
    
            requestData()
        }
        
        func requestData() {
            // I don't know the Firebase request signature, so here's a placeholder
            Firebase.requestData(completion: { result in
                 switch result {
                 case .success(let data):
                     self.model = data
                     // Then update your UI for data
                     
                 case .error(let error):
                     // Show error UI
                 }
            })
        }
        
        // UITableViewDataSource
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            // This depends on the design of your table view
            if let model = model {
                return model.things.count
                
            } else {
                // `model` is nil
                return 0
            }
        }
    }
    

    Option 2 might look like:

    class PrecedingViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
        // UITableViewDelegate
        func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
            // Show loading UI
            
            Firebase.requestData(completion: { result in
                 switch result {
                 case .success(let data):
                     // We have data, NOW load the New View Controller
                     let newViewController = NewViewController(model: data)
                     navigationController?.pushViewController(newViewController, animated: true)
                     
                 case .error(let error):
                     // Show error UI
                 }
            })
        }
    }
    

    Then:

    class NewViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
        let model: DataModel   // Non-optional, as we know we have a model
        
        init(model: DataModel) {
            self.model = model
            super.init(style: .grouped)
        }
        
        // UITableViewDataSource
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            // This depends on the design of your table view
            return model.things.count
        }
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search