iosswiftuitableviewxibnib

How to populate two different xib files in one UITableViewCell depending on a condition? in Swift


I have tableView that populates multiple cells. In one of the cell I want to populate 'xib1', if I have data in my array. But if I have 'nil' in my array I want to populate 'xib2' in the same tableview instead of 'xib1'.

How shall I achieve this behaviour in Swift.

I tried using condition say, if the array is nil show xib2 and if not show xib1. Didnt work. it loops in 2nd condition and keeps showing that data where as I want it to show rest of the cells as well which dont have any such conditions.


Solution

  • While the question describes displaying different .xib files conditionally dependent on the array's contents, it is much simpler to create two different subclasses of UITableViewCell, each with its own associated .xib, and then register both subclasses of cell for your table. This is what Duncan C is referring to in his comment.

    If you do this, determining which cell to display in the cellForRowAt method becomes very straightforward: just do a test for nil at the corresponding array index, and return a different cell based on the result. Below is a minimal example of this, which I've tested and confirmed works:

    VIEW CONTROLLER CODE

    import UIKit
    
    class ViewController: UIViewController {
        @IBOutlet weak var table: UITableView!
        
        var stuff: [String?] = ["abc", nil, "def", "ghi", nil, "jkl", nil, nil]
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            table.dataSource = self
            table.register(UINib(nibName: "Cell1", bundle: nil), forCellReuseIdentifier: "nonNilCell")
            table.register(UINib(nibName: "Cell2", bundle: nil), forCellReuseIdentifier: "nilCell")
        }
    }
    
    extension ViewController: UITableViewDataSource {
        func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
            return stuff.count
        }
        
        func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
            if stuff[indexPath.row] != nil {
                let cell = tableView.dequeueReusableCell(withIdentifier: "nonNilCell", for: indexPath) as! Cell1
                cell.label.text = stuff[indexPath.row]
                return cell
            } else {
                let cell = tableView.dequeueReusableCell(withIdentifier: "nilCell", for: indexPath) as! Cell2
                return cell
            }
        }
    }
    

    FIRST CELL (for non-nil array items)

    import UIKit
    
    // This is the cell for array entries that are not nil
    class Cell1: UITableViewCell {
        @IBOutlet weak var label: UILabel!
        
        override func awakeFromNib() {
            super.awakeFromNib()
        }
    
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
        }
    }
    

    SECOND CELL (for nil array items)

    import UIKit
    
    // This is the cell for array items which are nil
    class Cell2: UITableViewCell {
    
        override func awakeFromNib() {
            super.awakeFromNib()
        }
    
        override func setSelected(_ selected: Bool, animated: Bool) {
            super.setSelected(selected, animated: animated)
        }
    }
    

    And here are the two .xib files (the text on the green one changes to reflect the value from the array):

    non-nil cellnil cell