Showing property in tablecell

I am following a course and am trying so test myself.
I have a model and I give values to properties from a json-file.
(If Im showing code wrong please tell me how I shoud do it)


This works:

func updateUIWithWeatherData() {

cityLabel.text = weatherDataModel.city

temperatureLabel.text = String(weatherDataModel.temperature)

weatherIcon.image = UIImage(named: weatherDataModel.weatherIconName)

}


But here it doesn't. Test shows but not the city.

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

let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")

cell.textLabel?.text = weatherDataModel.city

//cell.textLabel?.text = "test"

return cell

}

Accepted Reply

But I can show a value set in


That has nothing to do with IBOutlet connection.


You need to open the storyboard editor and connect your Table View in design canvas to the IBOutlet `tableView` in the code.

Replies

//MARK: - Networking

/***************************************************************/

//Write the getWeatherData method here:

func getWeatherData(url: String, parameters: [String : String]) {

Alamofire.request(url, method: .get, parameters: parameters).responseJSON {

response in

if response.result.isSuccess {

//print("Success! Got the weather data")

let weatherJSON : JSON = JSON(response.result.value!)

self.updateWeatherData(json: weatherJSON)

//print(weatherJSON)

}

else {

print("Error \(String(describing: response.result.error))")

self.cityLabel.text = "Connection problem"

}

}

}

func getTrainData(url: String) {

Alamofire.request(url).responseJSON {

response in

if response.result.isSuccess {

//print("Success! Got the train data")

let trainJSON : JSON = JSON(response.result.value!)

self.updateTrainData(json: trainJSON)

//print(trainJSON)

}

else {

print("Error \(String(describing: response.result.error))")

self.cityLabel.text = "Connection problem"

}

}

}

//MARK: - JSON Parsing

/***************************************************************/


//Write the updateWeatherData method here:

func updateWeatherData(json : JSON) {

//let tempResult = json["main"]["temp"]

//print("Test", tempResult)

if let tempResult = json["main"]["temp"].double {

weatherDataModel.temperature = Int(tempResult - 273.15)

weatherDataModel.city = json["name"].stringValue

weatherDataModel.condition = json["weather"][0]["id"].intValue

weatherDataModel.weatherIconName = weatherDataModel.updateWeatherIcon(condition: weatherDataModel.condition)

updateUIWithWeatherData()

}

else {

cityLabel.text = "Väderdata kunde inte visas"

}

}

//Write the updateWeatherData method here:

func updateTrainData(json : JSON) {

//let tempResult = json["StopLocation"][2]["name"]

//let tempResult = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["name"].string

//print("Train", tempResult)



if let tempResult = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["name"].string {

trainDataModel.station = tempResult

trainDataModel.arrivalTime = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["arrTime"].stringValue

print(trainDataModel.arrivalTime)

updateUIWithTrainData()

}

else {

cityLabel.text = "Tågdata kunde inte visas"

}

}

//MARK: - UI Updates

/***************************************************************/

//Write the updateUIWithWeatherData method here:

func updateUIWithWeatherData() {

cityLabel.text = weatherDataModel.city

temperatureLabel.text = String(weatherDataModel.temperature)

weatherIcon.image = UIImage(named: weatherDataModel.weatherIconName)

}

func updateUIWithTrainData() {

//cityLabel.text = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["name"].stringValue

//temperatureLabel.text = String(weatherDataModel.temperature)

//weatherIcon.image = UIImage(named: weatherDataModel.weatherIconName)

//cityLabel.text = trainDataModel.station

//temperatureLabel.text = trainDataModel.arrivalTime

}

//MARK: - Location Manager Delegate Methods

/***************************************************************/

//Write the didUpdateLocations method here:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

let location = locations[locations.count - 1] //tar sista vördet

if location.horizontalAccuracy > 0 {

locationManager.stopUpdatingLocation()

locationManager.delegate = nil

print("longitude = \(location.coordinate.longitude), latitude = \(location.coordinate.latitude)")

let latitude = String(location.coordinate.latitude)

let longitude = String(location.coordinate.longitude)

let params : [String : String] = ["lat" : latitude, "lon" : longitude, "appid" : APP_ID]

getWeatherData(url : WEATHER_URL, parameters: params)

getTrainData(url: TRAIN_URL)

// cityLabel.text = "Hittade plats!"

}

}

//Write the didFailWithError method here:

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {

print(error)

cityLabel.text = "Hittar ej plats"

}

//MARK: - Change City Delegate methods

/***************************************************************/

//Write the userEnteredANewCityName Delegate method here:


//Write the PrepareForSegue Method here

//MARK: - TableView methods

/***************************************************************/

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

return 3

}

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

let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")

cell.textLabel?.text = weatherDataModel.city

//cell.textLabel?.text = "test"

return cell

}

}

OK, I copied in a single file and use code formatter to make it easier to read



import UIKit

class WeatherDataModel {
  
    //Declare your model variables here
    var temperature : Int = 0
    var condition : Int = 0
    var city : String = ""
    var weatherIconName : String = ""
  
    //This method turns a condition code into the name of the weather condition image
  
    func updateWeatherIcon(condition: Int) -> String {
      
        switch (condition) {
          
        case 0...300 :
            return "tstorm1"
          
        case 301...500 :
            return "light_rain"
          
        case 501...600 :
            return "shower3"
          
        case 601...700 :
            return "snow4"
          
        case 701...771 :
            return "fog"
          
        case 772...799 :
            return "tstorm3"
          
        case 800 :
            return "sunny"
          
        case 801...804 :
            return "cloudy2"
          
        case 900...903, 905...1000  :
            return "tstorm3"
          
        case 903 :
            return "snow5"
          
        case 904 :
            return "sunny"
          
        default :
            return "dunno"
        }
      
    }
}

class TrainDataModel {
  
    //Declare your model variables here
    var station : String = ""
    //var arrivalTime : Date? = nil
    var arrivalTime : String = ""
}

import CoreLocation

class WeatherViewController: UIViewController, CLLocationManagerDelegate, UITableViewDelegate, UITableViewDataSource {
  
    //Constants
    let APP_ID_TRAIN2 = ""
    let APP_ID_SEARCH_STATION = ""
    let WEATHER_URL =  ""
    let TRAIN_URL =  ""
    //let TRAIN_URL =
    let TRAIN_URL2 = ""
    let TRAIN_URL3 = ""
    let APP_ID = ""
  
    //TODO: Declare instance variables here
    let locationManager = CLLocationManager()
    let weatherDataModel = WeatherDataModel()
    let trainDataModel = TrainDataModel() //Object
  
    //Pre-linked IBOutlets
    @IBOutlet weak var weatherIcon: UIImageView!
    @IBOutlet weak var cityLabel: UILabel!
    @IBOutlet weak var temperatureLabel: UILabel!
   
    override func viewDidLoad() {
        super.viewDidLoad()
       
        //TODO:Set up the location manager here.
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters
        locationManager.requestWhenInUseAuthorization()
        locationManager.startUpdatingLocation()
}


    //MARK: - Networking
    /***************************************************************/
  
    //Write the getWeatherData method here:
    func getWeatherData(url: String, parameters: [String : String]) {
      
        Alamofire.request(url, method: .get, parameters: parameters).responseJSON {
            response in
            if response.result.isSuccess {
                //print("Success! Got the weather data")
              
                let weatherJSON : JSON = JSON(response.result.value!)
                self.updateWeatherData(json: weatherJSON)
                //print(weatherJSON)
            }
            else {
                print("Error \(String(describing: response.result.error))")
                self.cityLabel.text = "Connection problem"
            }
        }
    }
  
  
    func getTrainData(url: String) {
      
        Alamofire.request(url).responseJSON {
            response in
            if response.result.isSuccess {
                //print("Success! Got the train data")
              
                let trainJSON : JSON = JSON(response.result.value!)
                self.updateTrainData(json: trainJSON)
                //print(trainJSON)
            }
            else {
                print("Error \(String(describing: response.result.error))")
                self.cityLabel.text = "Connection problem"
            }
        }
      
}

    //MARK: - JSON Parsing
    /***************************************************************/
  
  
    //Write the updateWeatherData method here:
    func updateWeatherData(json : JSON) {
      
      
        //let tempResult = json["main"]["temp"]
      
        //print("Test", tempResult)
      
        if let tempResult = json["main"]["temp"].double {
          
            weatherDataModel.temperature = Int(tempResult - 273.15)
          
            weatherDataModel.city = json["name"].stringValue
          
            weatherDataModel.condition = json["weather"][0]["id"].intValue
          
            weatherDataModel.weatherIconName = weatherDataModel.updateWeatherIcon(condition: weatherDataModel.condition)
          
            updateUIWithWeatherData()
        }
        else {
            cityLabel.text = "Väderdata kunde inte visas"
        }
    }

    //Write the updateWeatherData method here:
    func updateTrainData(json : JSON) {
      
        //let tempResult = json["StopLocation"][2]["name"]
        //let tempResult = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["name"].string
        //print("Train", tempResult)
      
        if let tempResult = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["name"].string {
          
            trainDataModel.station = tempResult
          
            trainDataModel.arrivalTime = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["arrTime"].stringValue
          
            print(trainDataModel.arrivalTime)
          
            updateUIWithTrainData()
        }
        else {
            cityLabel.text = "Tågdata kunde inte visas"
        }
      
}

    //MARK: - UI Updates
    /***************************************************************/
  
    //Write the updateUIWithWeatherData method here:
  
    func updateUIWithWeatherData() {
      
        cityLabel.text = weatherDataModel.city
        temperatureLabel.text = String(weatherDataModel.temperature)
        weatherIcon.image = UIImage(named: weatherDataModel.weatherIconName)
    }
  
    func updateUIWithTrainData() {
      
        //cityLabel.text = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["name"].stringValue
        //temperatureLabel.text = String(weatherDataModel.temperature)
        //weatherIcon.image = UIImage(named: weatherDataModel.weatherIconName)
      
        //cityLabel.text = trainDataModel.station
        //temperatureLabel.text = trainDataModel.arrivalTime
      
     }          // Closing } missing here ?
}


Several questions: this is not the exact copy of your code ? It cannot compile.


1. Is all this inside the class WeatherViewController ?

If so, you need an } to end the class (added line 215)


2. Const are not defined (lines 70 to 77)

I added = ""


3. weatherDataModel.city is only set line 158 in updateWeatherData, which is called in getWeatherData

Are you sure you get there ? Could you reset the comments lines 109 and 113 and tell what you get ?


4. You have not included the func tableView() functions.


So, please post the complete and real code of the class, not skipping some parts that are critical, and use the code formatter (<>) to make it easier to read.

Well, I had trouble to post. I'll try again.
1. I think you missed some which is easy because of the way I posted. I probably missed the end of class.
2. The const I left out are the URL for the JSON-call. I try to leave the in using your proposed method. I leave some out that I only used for testing.


3. Yes, I'm sure I get there. In updateUIWithWeatherData() print out the value in a label, and that works.
4. I think I had that but as I said easy to miss. Placed the two functions needed for TableView last in the file.
Thank you for showing a way to easier show the code.


<

//

// ViewController.swift

// WeatherApp

//

// Created by Angela Yu on 23/08/2015.

// Copyright (c) 2015 London App Brewery. All rights reserved.

//


import UIKit

import CoreLocation

import Alamofire

import SwiftyJSON



class WeatherViewController: UIViewController, CLLocationManagerDelegate, UITableViewDelegate, UITableViewDataSource {



//Constants

let APP_ID_TRAIN2 = "9ad33f89-ad4d-4705-a7e9-b48a654064c6"

let APP_ID_SEARCH_STATION = "332b6bdc-5bb8-4ff3-8e71-870e78bb465c"

let WEATHER_URL = "h t t p: / / a p i.openweathermap.org/data/2.5/weather"

let TRAIN_URL = "h t t ps : / / a p i .resrobot.se/v2/trip?key=332b6bdc-5bb8-4ff3-8e71-870e78bb465c&originId=740098548&destId=740000006&format=json&products=16" //Sök mellan två platser



let APP_ID = "9b1864136739f58051bf9949784b3497"




//TODO: Declare instance variables here

let locationManager = CLLocationManager()

let weatherDataModel = WeatherDataModel()

let trainDataModel = TrainDataModel() //Object


//Pre-linked IBOutlets

@IBOutlet weak var weatherIcon: UIImageView!

@IBOutlet weak var cityLabel: UILabel!

@IBOutlet weak var temperatureLabel: UILabel!



override func viewDidLoad() {

super.viewDidLoad()



//TODO:Set up the location manager here.

locationManager.delegate = self

locationManager.desiredAccuracy = kCLLocationAccuracyHundredMeters

locationManager.requestWhenInUseAuthorization()

locationManager.startUpdatingLocation()



}



//MARK: - Networking

/***************************************************************/


//Write the getWeatherData method here:

func getWeatherData(url: String, parameters: [String : String]) {


Alamofire.request(url, method: .get, parameters: parameters).responseJSON {

response in

if response.result.isSuccess {

print("Success! Got the weather data")

let weatherJSON : JSON = JSON(response.result.value!)

self.updateWeatherData(json: weatherJSON)

print(weatherJSON)

}

else {

print("Error \(String(describing: response.result.error))")

self.cityLabel.text = "Connection problem"

}

}

}



func getTrainData(url: String) {


Alamofire.request(url).responseJSON {

response in

if response.result.isSuccess {

//print("Success! Got the train data")

let trainJSON : JSON = JSON(response.result.value!)

self.updateTrainData(json: trainJSON)

//print(trainJSON)

}

else {

print("Error \(String(describing: response.result.error))")

self.cityLabel.text = "Connection problem"

}

}


}




//MARK: - JSON Parsing

/***************************************************************/



//Write the updateWeatherData method here:

func updateWeatherData(json : JSON) {



//let tempResult = json["main"]["temp"]


//print("Test", tempResult)


if let tempResult = json["main"]["temp"].double {


weatherDataModel.temperature = Int(tempResult - 273.15)


weatherDataModel.city = json["name"].stringValue


weatherDataModel.condition = json["weather"][0]["id"].intValue


weatherDataModel.weatherIconName = weatherDataModel.updateWeatherIcon(condition: weatherDataModel.condition)


updateUIWithWeatherData()

}

else {

cityLabel.text = "Väderdata kunde inte visas"

}

}

//Write the updateWeatherData method here:

func updateTrainData(json : JSON) {


//let tempResult = json["StopLocation"][2]["name"]

//let tempResult = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["name"].string

//print("Train", tempResult)




if let tempResult = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["name"].string {


trainDataModel.station = tempResult


trainDataModel.arrivalTime = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["arrTime"].stringValue


print(trainDataModel.arrivalTime)


updateUIWithTrainData()

}

else {

cityLabel.text = "Tågdata kunde inte visas"

}


}



//MARK: - UI Updates

/***************************************************************/



//Write the updateUIWithWeatherData method here:


func updateUIWithWeatherData() {


cityLabel.text = weatherDataModel.city

temperatureLabel.text = String(weatherDataModel.temperature)

weatherIcon.image = UIImage(named: weatherDataModel.weatherIconName)



}


func updateUIWithTrainData() {


//cityLabel.text = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["name"].stringValue

//temperatureLabel.text = String(weatherDataModel.temperature)

//weatherIcon.image = UIImage(named: weatherDataModel.weatherIconName)


//cityLabel.text = trainDataModel.station

//temperatureLabel.text = trainDataModel.arrivalTime


}



//MARK: - Location Manager Delegate Methods

/***************************************************************/



//Write the didUpdateLocations method here:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

let location = locations[locations.count - 1] //tar sista vördet

if location.horizontalAccuracy > 0 {

locationManager.stopUpdatingLocation()

locationManager.delegate = nil


print("longitude = \(location.coordinate.longitude), latitude = \(location.coordinate.latitude)")


let latitude = String(location.coordinate.latitude)

let longitude = String(location.coordinate.longitude)


let params : [String : String] = ["lat" : latitude, "lon" : longitude, "appid" : APP_ID]


getWeatherData(url : WEATHER_URL, parameters: params)


getTrainData(url: TRAIN_URL)



// cityLabel.text = "Hittade plats!"


}

}



//Write the didFailWithError method here:

func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {

print(error)

cityLabel.text = "Hittar ej plats"

}



//MARK: - Change City Delegate methods

/***************************************************************/



//Write the userEnteredANewCityName Delegate method here:




//Write the PrepareForSegue Method here




//MARK: - TableView methods

/***************************************************************/


func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {

return 3

}


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


let cell = UITableViewCell(style: .default, reuseIdentifier: "Cell")


cell.textLabel?.text = weatherDataModel.city


//cell.textLabel?.text = "test"


return cell



}

}






>

Hi! I really appreciate your help.
I am trying to post in one file but keep getting the message "being moderated"
Thinking that the links are the problem I removed som of the link for weather_URL and TRAIN_URL.
Weather_URL are from the course I'm following and TRAIN_URL are my own testing.
If the file is approved I have tried to anwer your question.


The removal of the links didn't seem to help, and you need the links anyway. Adding space didn't seem to help-
If you doesn't have a solution I just have to wait until it is approved.

Thanks for showing your code.


As far as I checked your currently visible code:


- Your WeatherViewController lacks the property holding the UITableView, you usually make it an IBOutlet and connect it on the storyboard.

class WeatherViewController: UIViewController, CLLocationManagerDelegate, UITableViewDelegate, UITableViewDataSource {
    //...
    
    @IBOutlet weak var tableView: UITableView! //<-

    //...
}

- You are not setting the delegate and the dataSource of the table view in code. You can do it on the storyboard, but I recommend you to do it by code.

    override func viewDidLoad() {
        super.viewDidLoad()
        
        tableView.delegate = self   //<-
        tableView.dataSource = self //<-

        //...
    }


- You are not calling `reloadData()` when the models are updated.

    func updateUIWithWeatherData() {
        
        cityLabel.text = weatherDataModel.city
        temperatureLabel.text = String(weatherDataModel.temperature)
        weatherIcon.image = UIImage(named: weatherDataModel.weatherIconName)
        
        tableView.reloadData() //<-
    }
    
    func updateUIWithTrainData() {
        
        //cityLabel.text = json["Trip"][0]["LegList"]["Leg"][0]["Stops"]["Stop"][1]["name"].stringValue
        //temperatureLabel.text = String(weatherDataModel.temperature)
        //weatherIcon.image = UIImage(named: weatherDataModel.weatherIconName)
        
        //cityLabel.text = trainDataModel.station
        //temperatureLabel.text = trainDataModel.arrivalTime
        
        tableView.reloadData() //<-
    }


Of course your `tableView(_:cellForRowAt:)` should be updated as suggested by Claude31.

Thanks! I will try your suggestions when I am at my computer again. I am kind of a beginner and haven’t fully graspt everything. My approach is to make my own app while learning.

So this is what I get after trying the suggestions from OOPer.
Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
I think I somewhat understand Optionals but not entirely.
It does suggest I guess that the object in tableView is empty. I don't understand why since.it's set in updateWeatherData.

I have already connected to delegate and source in storyboard if that matters.

When you get Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value, the first thing you need to do is finding on which line this runtime-error has occurred.


Something is nil, that should not be nil included in the line.


For example, if you get that error on this line:

tableView.delegate = self

Then `tableView` is nil, that should not be nil. This happens when you do not connect the IBOutlet properly.


So, on which line that is happening?

Yes, it is at the line

tableView.delegate = self
That the error fist occurs.

But I can show a value set in
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {


But not the value from the model.
So I can do


cell.textLabel?.text = "test"


But not


cell.textLabel?.text = self.weatherDataModel.city


But I know that the value is set in function


updateWeatherData



Key question: have you checked that tableView IBOutlet is effectively connected to the UITableView in IB ?

Not sure.
I connected the outlet to source and delegate.
If this was working I'm not sure.
How can I check this?

But I can show a value set in


That has nothing to do with IBOutlet connection.


You need to open the storyboard editor and connect your Table View in design canvas to the IBOutlet `tableView` in the code.