lysov
lysov

Reputation: 160

Content of a cell in static tableview isn't shown SWIFT 3

Here is my implementation of tableView(_:cellForRowAt:):

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let index = indexPath.section
    let weekDay = WeekDays.day(at: index)
    if self.availability.numberOfTimeslots(for: weekDay) == 0 {
        let cell = NotSelectedCell(style: .default, reuseIdentifier: nil)
        return cell
    }

    return UITableViewCell()
}

Here is my code for my custom table view cell:

class NotSelectedCell: UITableViewCell {

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code

        self.backgroundColor = .red
        self.textLabel?.numberOfLines = 0
        self.textLabel?.textAlignment = .center;
        self.textLabel?.text = "Not Available"
    }

}

I've also tried initializing custom cell cell = NotSelectedCell() the result is the same. The content isn't shown. dataSource or viewDelegate aren't the problem as I'm working with UITableViewController.

Here's an image enter image description here

Upvotes: 1

Views: 779

Answers (2)

Rob
Rob

Reputation: 437392

The problem is awakeFromNIB "prepares the receiver for service after it has been loaded from an Interface Builder archive, or nib file." But you're instantiating this programmatically, so that method isn't called. You could theoretically move the code to init(style:reuseIdentifier:), make sure to call super in your implementation, and do any additional customization after that point.

But, you generally wouldn't programmatically instantiate cells when using static cells. (It's the point of static cells, that IB takes care of everything for you.) You generally don't implement UITableViewDataSource at all when using static cells.

I would advise using dynamic table and have two cell prototypes, one with reuse identifier of "NotAvailable" and one with "Available" (or whatever identifiers you want). Then programmatically instantiate the cell with the appropriate identifier. (By the way, this also has the virtue that your cell with "NotAvailable" can be designed entirely in IB, and no code is needed, for that cell at least.) This way, the storyboard takes care of instantiating the appropriate cell.

So, here I have two cell prototypes in my dynamic table, one for "not available" and one for "available":

enter image description here

Then the code would look at the model to figure out which to instantiate:

// for the complicated cell where I want to show details of some window of availability, add IBOutlets for that cell's labels

class AvailableCell: UITableViewCell {
    @IBOutlet weak var startLabel: UILabel!
    @IBOutlet weak var stopLabel: UILabel!
    @IBOutlet weak var doctorLabel: UILabel!
}

// some super simple model to represent some window of availability with a particular doctor in that office

struct Availability {
    let start: String
    let stop: String
    let doctor: String
}

class ViewController: UITableViewController {

    let days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]

    let available = ...

    override func numberOfSections(in tableView: UITableView) -> Int {
        return days.count
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return available[days[section]]?.count ?? 1
    }

    override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return days[section]
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        // see if there are any available windows for the given day, if not, return "not available" cell

        guard let availabilities = available[days[indexPath.section]] else {
            return tableView.dequeueReusableCell(withIdentifier: "NotAvailable", for: indexPath)
        }

        // otherwise, proceed with the more complicated "Available" cell where I have to populate various labels and the like

        let cell = tableView.dequeueReusableCell(withIdentifier: "Available", for: indexPath) as! AvailableCell

        let availability = availabilities[indexPath.row]
        cell.startLabel.text = availability.start
        cell.stopLabel.text = availability.stop
        cell.doctorLabel.text = availability.doctor

        return cell
    }
}

And that would yield:

enter image description here

Now, clearly, I just whipped up a super primitive model, and didn't do any UI design in the "available" cell prototype other than inserting three labels. But it illustrates the idea: If your dynamic table has multiple unique cell designs, just implement cell prototypes for each with unique identifiers and instantiate the appropriate one. And this way, you enjoy full cell reuse, minimize how much visual design you have to do programmatically, etc.

Upvotes: 1

Pochi
Pochi

Reputation: 13459

You are not supposed to use the cellForRow:atIndexPath method when using static cells. The cells are static, so the loading flow is different. What i'd suggest is to connect the cells individually from the interface builder to your view controller.

STILL, if you want to do it this way you have to get your cells by calling "super" since that's the class who is actually generating your static cells.

UITableView with static cells without cellForRowAtIndexPath. How to set clear background?

EDIT:

I just noticed that this is wrong:

if self.availability.numberOfTimeslots(for: weekDay) == 0 {
    let cell = NotSelectedCell(style: .default, reuseIdentifier: nil)
    return cell
} 

You have to use the "dequeueReusable" method or something. Then again, these are STATIC Cells, so you should just be linking the cells directly from the interface builder.

Upvotes: 0

Related Questions