The Mysterious UITableView Case

Standard

Preambule

We have recently converted our project from Swift 2.3 to Swift 3. And everything was good so far until I didn’t have to create new screen that contained Table View. Pretty basic task, huh? Well, one problem appeared and I literally spent one hour trying to resolve this.

Ok let me get to the description of the case itself.

Case description

Below you can find very basic example of code that illustrates the issue:

import UIKit

class ViewController: UIViewController {
     @IBOutlet weak var tableView: UITableView!

     override func viewDidLoad() {
          super.viewDidLoad()

          let view = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: .min))
          self.tableView.tableHeaderView = view
          self.tableView.tableFooterView = view

          self.tableView.dataSource = self
          self.tableView.delegate = self

          self.tableView.reloadData()
      }
}

extension ViewController: UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }

     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         var cell: UITableViewCell!

         if let newCell = tableView.dequeueReusableCell(withIdentifier: "WHAT IS THE KAPPA") {
              cell = newCell
         } else {
              cell = UITableViewCell.init(style: .default, reuseIdentifier: "WHAT IS THE KAPPA")
         }

         cell.textLabel?.text = "O_O"
         return cell
    }
}

extension ViewController: UITableViewDelegate {
     func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 44.0
     }
}

Seems to be ok, builds without errors and even without warnings, what can go wrong, huh?

Well, if you actually build and run this code you will get something like this:screen-shot-2017-03-02-at-5-19-47-pm

Erm, where did the Table View go?

Solution

I met this issue and spent like 1 hour debugging and searching, what can cause such problem. Basically, if you will try to debug this code you will see that functions:

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 5
    }
     func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return 44.0
     }

are actually getting called. However, function:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
         var cell: UITableViewCell!

         if let newCell = tableView.dequeueReusableCell(withIdentifier: "WHAT IS THE KAPPA") {
              cell = newCell
         } else {
              cell = UITableViewCell.init(style: .default, reuseIdentifier: "WHAT IS THE KAPPA")
         }

         cell.textLabel?.text = "O_O"
         return cell
    }

is not fired even one time.

toll_face

Basically, solution came to me in pretty random way. I looked up on the setup of Table View and saw following:

let view = UIView(frame: CGRect(x: 0, y: 0, width: 0, height: .min))
self.tableView.tableHeaderView = view
self.tableView.tableFooterView = view

Seems rather normal, doesn’t it? Well, one thing caught my eye on this – it’s small dirty “.min” at the end of the first line.

I thought: “Wasn’t it changed to something else?”. Fast search in the codebase give that “.min” was changed to “CGFloat.leastNormalMagnitude”. Let’s try to change “.min” to “CGFloat.leastNormalMagnitude” in the line above and run it:
screen-shot-2017-03-02-at-5-35-57-pm

Bingo!

The most confusing thing for me was compiler wasn’t complaining about it at all and it somehow prevented cellForRow being called, while other function were working just fine.

I hope that it might help someone to resolve this quite strange and frustrating issue.

Good luck in bug hunting!

 

 

Advertisements