Need help converting JSON objects from double & floats to strings

I'm using the Openweathermap API to make calls and I'm building my app to display the results in a tableview, with the 4 results per call displayed in one tableview cell, each with their own label.

The struct I have set up for the results that I want is

struct MappedResult {
  var locationName: String
  var temperatureInF: Double
  var longitude: Float
  var latitude: Float
}

I initialize this struct in my ViewController as

var myResult: MappedResult = MappedResult(
    locationName: "String",
    temperatureInF: 0,
    longitude: 0,
    latitude: 0
 )

var myTableViewData: [MappedResult] = []

and further down in the VC, in my tableView func I have

 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
     
    let rowPosition: Int = indexPath.item
    let myApiResultItem: MappedResult = myTableViewData[rowPosition]
     
    let dequeuedCell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: C.cellIdentifier, for: indexPath)
     
    let weatherCell = dequeuedCell as! MyWeatherTableViewCell
     
    weatherCell.connectLabels(
      loc: myApiResultItem.locationName,
      temp: myApiResultItem.temperatureInF,
      lat: myApiResultItem.latitude,
      long: myApiResultItem.longitude)
    
    weatherCell.backgroundColor = .systemGray

    return weatherCell
  }

I have a separate class set up for the labels, and this is where I'm having trouble. I can't figure out how to convert the floats and double to string types so their data can be displayed in their labels.

I've tried Googling about how to change the types, I've searched the error, I've tried type casting (don't know much about it), declaring them as you see them now, and I came across a NumberFormatter func but don't know if that's the right thing to use, or even how to implement it.

class MyWeatherTableViewCell: UITableViewCell {

  @IBOutlet weak var locationLabel: UILabel!
  @IBOutlet weak var tempInFLabel: UILabel!
  @IBOutlet weak var longLabel: UILabel!
  @IBOutlet weak var latLabel: UILabel!
   
   
   
  override func awakeFromNib() {
    super.awakeFromNib()
    // Initialization code
     
  }

  override func setSelected(_ selected: Bool, animated: Bool) {
    super.setSelected(selected, animated: animated)

    // Configure the view for the selected state
  }
   
   
   
  func connectLabels(loc: String, temp: Double, lat: Float, long: Float) {
    locationLabel.text = loc
    Double(tempInFLabel.text!) = temp  **
    Float(latLabel.text!) = lat **
    Float(longLabel.text!) = long **
    
   }
}

The last three labels with the ** have the error

Expression is not assignable: function call returns immutable value.

How do I fix this? Thanks.

Answered by Claude31 in 676705022

You are trying to have a "reverse cast" !You cannot write:

    Double(tempInFLabel.text!) = temp **

But you should write

    tempInFLabel.text = String(temp)

You can also format this to have a fixed number of decimals (here, 2 decimals):

tempInFLabel.text = String(format: "%.2f", temp)
latLabel.text = String(format: "%.2f", lat)
longLabel.text = String(format: "%.2f", long)

Accepted Answer

You are trying to have a "reverse cast" !You cannot write:

    Double(tempInFLabel.text!) = temp **

But you should write

    tempInFLabel.text = String(temp)

You can also format this to have a fixed number of decimals (here, 2 decimals):

tempInFLabel.text = String(format: "%.2f", temp)
latLabel.text = String(format: "%.2f", lat)
longLabel.text = String(format: "%.2f", long)

Thanks that fixed the issue. I am experiencing another one though, related to the same function.

If I set the labels as you did with the String(format: "%.2f", lat) then the app will crash due to Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value but if I remove the formatting part, it doesn't crash.

As already noted, when you need to convert Float/Double to String for assignment, you need to do it in the right hand side.

So, this would be the minimal code:

    func connectLabels(loc: String, temp: Double, lat: Float, long: Float) {
        locationLabel.text = loc
        tempInFLabel.text = String(temp)
        latLabel.text = String(lat)
        longLabel.text = String(long)
    }

But if you want to make your app sort of practical in the future, you should better use NumberFormatter for user readable values. Also, some users want temperatures shown in the unit they accustomed to, we use Celsius usually.

So, some practical code would be something like this:

    static let tempFormatter: MeasurementFormatter = {
        let mf = MeasurementFormatter()
        //You may want to modify these as you like...
        mf.unitStyle = .medium
        mf.numberFormatter.maximumFractionDigits = 1
        return mf
    }()
    
    static let latLongFormatter: NumberFormatter = {
        let nf = NumberFormatter()
        //You may want to modify these as you like...
        nf.usesSignificantDigits = true
        nf.minimumSignificantDigits = 5
        nf.maximumSignificantDigits = 5
        return nf
    }()
    
    func connectLabels(loc: String, temp: Double, lat: Float, long: Float) {
        locationLabel.text = loc
        let tempMeasurement = Measurement(value: temp, unit: UnitTemperature.fahrenheit)
        tempLabel.text = MyWeatherTableViewCell.tempFormatter.string(from: tempMeasurement)
        latLabel.text = MyWeatherTableViewCell.latLongFormatter.string(from: lat as NSNumber)
        longLabel.text = MyWeatherTableViewCell.latLongFormatter.string(from: long as NSNumber)
    }

Thanks!!

Need help converting JSON objects from double & floats to strings
 
 
Q