Table view cell issues

I am have been trying to solve this issue all day, but I just can't seem to find the problem. My code is not showing any errors, which in this case it might have been easier. The issue is that I can't get my custom table view cell to show when simulating the app. I have gone through this process before and there have never been this kind of problem. Outside of my view controller I have a table view controller and a table view cell controller (to customize the cell). I have linked the table view controller with my table view controller storyboard, and I have given the table cell an identifier. I also have another file (Forecast.swift) dedicated to parse the JSON.


Any idea of what I am doing wrong?


Below is my code from table view controller:

import UIKit
import Alamofire
import CoreLocation
class ForecastTableViewController: UITableViewController, CLLocationManagerDelegate {

    let locationManager = CLLocationManager()
    var currentLocation: CLLocation!


    var forecast: Forecast!
    var forecasts = [Forecast]()


    func downloadForecastData(completed: DownloadComplete) {
        Alamofire.request(FORECAST_URL, withMethod: .get, parameters: nil, encoding: .json).responseJSON { response in
            let result = response.result
         
            if let dict = result.value as? Dictionary<String, AnyObject> {
             
                if let list = dict["list"] as? [Dictionary<String, AnyObject>] {
                 
                    for obj in list {
                        let forecast = Forecast(weatherDict: obj)
                        self.forecasts.append(forecast)
                        print(obj)
                    }
                    self.forecasts.remove(at: 0)
                    self.tableView.reloadData()
                }
            }
         
            completed()
        }
    }
    override func viewDidLoad() {
        super.viewDidLoad()
     
        tableView.delegate = self
        tableView.dataSource = self
        self.tableView.register(ForecastCell.self, forCellReuseIdentifier: "forecastCell")
     
    }
  
    override func viewDidAppear(_ animated: Bool) {
        locationAuthStatus()
    }

    func locationAuthStatus() {
        if CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
            currentLocation = locationManager.location
            Location.sharedInstance.latitude = currentLocation.coordinate.latitude
            Location.sharedInstance.longitude = currentLocation.coordinate.longitude
            self.downloadForecastData(completed: {})
         
        } else {
            locationManager.requestWhenInUseAuthorization()
            locationAuthStatus()
        }
    }

    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return forecasts.count
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     
     
        if let cell = tableView.dequeueReusableCell(withIdentifier: "forecastCell", for: indexPath) as? ForecastCell {
         
            let forecast = forecasts[indexPath.row]
            cell.configureCell(forecast: forecast)
            return cell
        } else {
            return ForecastCell()
        }
}
}


And here is my code for the custom table cell:

import UIKit
class ForecastCell: UITableViewCell {
    /
    @IBOutlet weak var weatherTypeImage: UIImageView!
    @IBOutlet weak var currentTempLabel: UILabel!
    @IBOutlet weak var maxTempLabel: UILabel!
    @IBOutlet weak var minTempLabel: UILabel!
    @IBOutlet weak var weekdayLabel: UILabel!
    @IBOutlet weak var weatherTypeLabel: UILabel!
  
  
  
    func configureCell(forecast: Forecast) {
  
        minTempLabel.text = "\(forecast.minTemp)"
        maxTempLabel.text = "\(forecast.maxTemp)"
        currentTempLabel.text = "\(forecast.forecastTemp)"
        weatherTypeLabel.text = forecast.weatherType
        weekdayLabel.text = forecast.date
        weatherTypeImage.image = UIImage(named: forecast.weatherType)
      
  
    }
}

You're doing something odd here. When you register a class for the table cell view, that means cells are created by instantiating the class, and that would mean all the outlets in ForecastCell are going to be nil (because it's the NIB loading process that sets outlets for you). So how come you're not crashing (with a nil optional) in configureCell? Did you also create a prototype cell in the storyboard which also has identifier "forecastCell"? Did you set a custom class of "ForecastCell" on the cell in the storyboard too? If you did those last 2 things, you don't need to register the "ForecastCell" manually.


You also mentioned a "table cell view controller". What is that? It's not a standard design pattern.


Does your code ever take the "else" branch that returns ForecastCell()? Aside from the fact that that's not going to work because you don't configure the cell, this branch should never be taken because dequeueReusableCell only returns nil if it can find or create a new cell. A nil return seems like an unrecoverable error. However, if there's something else wrong and you're getting nil returns, that might explain your symptoms.

Hello QuiencyMorris,


Thank you for taking your time and helping me out.


I have indeed created a prototype cell in my storyboard that has the identifier "forecastCell", and I have given that prototype cell the class of "ForecastCell". I know this should be enough to but since it was not working I also tried to register the "ForecastCell" manually.


My bad when it comes to "table cell view controller", I was just referring to the "ForecastCell.swift."


I belive the code always takes the else branch, but that can just be my inexperiance talking. When you say I never configure the cell, what am I missing. I though this piece of code would do the job.


override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    
    
        if let cell = tableView.dequeueReusableCell(withIdentifier: "forecastCell", for: indexPath) as? ForecastCell {
        
            let forecast = forecasts[indexPath.row]
            cell.configureCell(forecast: forecast)
            return cell
        } else {
            return ForecastCell()
        }
}


Thank you again for the help, and I am looking forward to getting this solved with you.


For your information, here is the code for my "Foreast.swift" class:

import UIKit
import Alamofire
class Forecast {
   
    var _date: String!
    var _weatherType: String!
    var _forecastTemp: String!
    var _maxTemp: String!
    var _minTemp: String!
   
    var date: String {
        if _date == nil {
            _date = ""
       
        }
        return _date
    }
   
    var weatherType: String {
        if _weatherType == nil {
            _weatherType = ""
           
        }
        return _weatherType
    }
   
    var forecastTemp: String {
        if _forecastTemp == nil {
            _forecastTemp = ""
           
        }
        return _forecastTemp
    }
   
    var maxTemp: String {
        if _maxTemp == nil {
            _maxTemp = ""
           
        }
        return _maxTemp
    }
   
    var minTemp: String {
        if _minTemp == nil {
            _minTemp = ""
           
        }
        return _minTemp
    }
   
    init(weatherDict: Dictionary<String, AnyObject>) {
       
        if let temp = weatherDict["temp"] as? Dictionary<String, AnyObject> {
           
            if let forecastTemp = temp["day"] as? Double {
               
                let kelvinToCelsius = Double(round(forecastTemp - 273.15))
                self._forecastTemp = "\(kelvinToCelsius)"
               
            }
           
            if let minTemp = temp["min"] as? Double {
               
                let kelvinToCelsius = Double(round(minTemp - 273.15))
                self._minTemp = "\(kelvinToCelsius)"
               
            }
           
            if let maxTemp = temp["max"] as? Double {
               
                let kelvinToCelsius = Double(round(maxTemp - 273.15))
                self._maxTemp = "\(kelvinToCelsius)"
               
            }
           
        }
       
        if let weather = weatherDict["weather"] as? [Dictionary<String, AnyObject>] {
           
            if let main = weather[0]["main"] as? String {
               
                self._weatherType = main
               
            }
           
        }
       
        if let date = weatherDict["dt"] as? Double {
           
            let unixConvertedDate = Date(timeIntervalSince1970: date)
            let dateFormatter = DateFormatter()
            dateFormatter.dateStyle = .long
            dateFormatter.dateFormat = "EEE"
            dateFormatter.timeStyle = .none
            self._date = unixConvertedDate.dayOfTheWeek()
           
        }
    }
}
extension Date {
    func dayOfTheWeek() -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "EEE"
        return dateFormatter.string(from: self)
    }
}

>> I belive the code always takes the else branch


You should set a breakpoint inside tableCell(_:cellForRowAt:) and watch the flow of execution, to see what branch it actually takes.


If a nil cell is obtained, then you need to start investigating why. Now that I check the documentation, the dequeueReusableCell variant that you're using (the one with the 'for:' parameter) will never return nil.


So, the reason for the nil return must be that the "as? ForecastCell" cast fails. That would happen if the class of your prototype cell is wrong in the storyboard. Whatever is wrong is probably something simple but non-obvious. Make sure that the correct module is shown below the class name (typically "current" unless the class is defined in a different module), and that the table is set to dynamic rows, not static rows.


(If you break the "let cell = …" statement into two parts:


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


you can use the debugger to find out what the actual class of "cell" is after the first line.)


>> When you say I never configure the cell, what am I missing.


If the "else" branch is taken, you create a ForecastCell object, but you don't invoke "configureCell" on it before returning. That means none of the subviews will be given a non-nil value.


But the point is that the "else" branch shouldn't be there at all. You should always get a valid cell from the "if" branch.

^^This is how it looks for my table view cell from the storyboard. I believe that it is correct. After removing the the else branch it made no difference, so the flow of execution takes the if branch. Strange enough I ran you code (braking the "let cell" statement into two parts) but got nothing from the debugger. And as you said I do belive it is something simple but non-obvious, that is why it's so frustrating. I deleted the "ForecastCell" class a created an identical one to see if there were some internal errors with the class, but nothing changed. From a code perspective I am all good, it is something with the storyboard that messes it all up, right?


Thanks again for all the help, truly appreciated.

>> This is how it looks for my table view cell from the storyboard


Unfortuntely the forums don't show inline images. However, if you removed the "else" branch and there's no crash, the cell must be being created correctly, so the problem is elsewhere.


You could try using the Xcode view debugger (the Debug View Hierarchy button in the debugging toolbar). That should give you an idea of where the cell subviews are and how big they are.

Did you have anything specific in mind that I should look for in the Hierarchy view? What do you mean with how big the subview are? I have looked aroung myself and seen quite some duplets, for example 2 UIWindow, 2 UIImage, etc.

You should look where (say) the first row of your table should be. Can you locate the label views? Are they in the right place? Are they of the correct size? The idea is to find exactly what's missing.

I can't find any of my labels in the hierarchy, and the actual cusotm cell doesn't show up in the hierarchy as well. As previusly mentioned there are 2 UIImages, but I only use on in every cell. So there is for sure a problem here, what I already have done before is to recreate the the whole cell, that gave no effect though.


Yet again, your help is awesome!

Just to clarify: are you sure that there are any rows being created? What you're describing make it sound like the number of rows is 0.

I am 100% sure that the table view is created, I am getting the rows I am looking for. It is the cell that is non-existent.

And the fun thing is that I created another table view for another purpose with the same setup (custom table cell, etc), and that works more than fine. By the way would you like me to send the project to you so that you can get a better understading of what I am doing?

https://github.com/Ceonn/Weather-app


^^Here is my git for this project.

If you want to post [a version of] your project on DropBox, other eyes might spot the One Thing.


However, it's really become a debugging strategy problem. Keep in mind:


— If there's no bug where you're looking, perhaps you're looking in the wrong place. (This works better as the joke about looking for a dropped coin under the lamppost, because there's more light there than across the street where you actually dropped it.)


— The best kind of bug is one that's both gross and repeatable.


One issue to keep in mind is that it's possible to have created 2 table views on top of each other, and customized the one that isn't actually visible. This sounds unlikely, but it does happen from time to time.

Haha, I guess so. I have put a link to my Git to my project in an earlier reply (but that reply is currently being moderated, since it is a link). So to make it a game you can got to github / ceonn / weaather-app. Be aware of some unfinished code, my latest commit is named, "QuinceyMorris - commit."

Table view cell issues
 
 
Q