Search code examples
iosswiftuitableviewuistackview

UITableView embedded in a UIStackView is not reloading data


I have a tableView I am trying to populate with data. But the data is never loaded. The delegate method numberOfRowsInSection is called, but cellForRowAt isn't.

Interface Builder

enter image description here

Simulator Run

enter image description here

XCode Console

enter image description here

View Debugger

enter image description here

enter image description here

Can anyone see what I am doing wrong?

class ChargeDetailsView: UIView {

    @IBOutlet weak var chargesTable: UITableView!
    @IBOutlet weak var tvSubtotalAmount: UILabel!
    @IBOutlet weak var tvDiscountsAmount: UILabel!
    @IBOutlet weak var tvTaxesAmount: UILabel!
    @IBOutlet weak var tvGrandTotalAmount: UILabel!
    
    private var allCharges:[ServiceLineItem] = []
    
    class func instanceFromNib() -> UIView {
        return UINib(nibName: "ChargeDetailsView", bundle: Bundle(for: ChargeDetailsView.self)).instantiate(withOwner: nil, options: nil)[0] as! UIView
    }
    
    public override func awakeFromNib() {
        super.awakeFromNib()
        print("ChargeDetailsView awakeFromNib")
        self.chargesTable.delegate = self
        self.chargesTable.dataSource = self
        self.chargesTable.register(ServiceLineItemCell.nib(), forCellReuseIdentifier: ServiceLineItemCell.identifier)
        
        self.tvSubtotalAmount.text = "-"
        self.tvDiscountsAmount.text = "-"
        self.tvTaxesAmount.text = "-"
        self.tvGrandTotalAmount.text = "-"
        
    }
    
    public func configure(with details: GetReceiptDetails){
        self.tvSubtotalAmount.text = "-"
        self.tvDiscountsAmount.text = "-"
        self.tvTaxesAmount.text = "-"
        self.tvGrandTotalAmount.text = "-"
        
        if let priceSubtotal = details.priceSubtotal {
            self.tvSubtotalAmount.text = String(format: "$%.02f", Double(priceSubtotal))
        }
        
        if let priceDiscount = details.priceDiscount {
            self.tvDiscountsAmount.text = String(format: "$%.02f", Double(priceDiscount))
        }
        
        if let priceTax = details.priceTax {
            self.tvTaxesAmount.text = String(format: "$%.02f", Double(priceTax))
        }
        
        if let priceTotal = details.priceTotal {
            self.tvGrandTotalAmount.text = String(format: "$%.02f", Double(priceTotal))
        }
        
        if details.pricing != nil, let items = details.pricing?.lineItems, items.count > 0 {
            allCharges.removeAll()
            allCharges.append(contentsOf: items)
            print("allCharges total items: \(allCharges.count)")
        
            self.chargesTable.reloadData()
        }
    }
}


extension ChargeDetailsView: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        print("ChargeDetailsView numberOfRowsInSection: \(allCharges.count)")
        return allCharges.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        print("row: \(indexPath.row)")
        let cell = tableView.dequeueReusableCell(withIdentifier: ServiceLineItemCell.identifier) as! ServiceLineItemCell
        cell.configure(with: allCharges[indexPath.row])
        return cell
    }
    
    func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
        return UITableView.automaticDimension
    }
}

Solution

  • Typically, when a table view never asks the data source for cells, it's because the table view has no size. I guess the runtime figures that since the table view has no size, it can't display any cells, so it doesn't need to ask for any.

    In this particular case, your table view is inside a vertical stack view. A stack view, in some configurations, depends on the inherent height of its arranged subviews to know how to size them. A label, for instance, has an inherent height (the height of its intrinsicContentSize).

    But a table view has no inherent height; you have to give it one. Otherwise, the table view's height will be zero — and that's why you don't see it, and why it isn't being asked for cells.

    Either you need to apply an absolute height constraint on the table view, or you need to implement the table view's intrinsicContentSize (or similar) in such a way as to determine the height. The stack view will then take that into account, the table view will have height, the data source will be asked for cells, and you'll start to see something in the table view.