Xenophiliac
Xenophiliac

Reputation: 191

Error when unwrapping a optional

In the following code I get an error from xcode saying: "Cannot use mutating member on immutable value: 'fahrenheitValue' is a 'let' constant."

This code sample is from The Big Nerd Ranch Guide for iOS 6th edition. A part from not really understanding why the book would be wrong, I understand the meaning of the error but I don't get how I could work around this...

Could somebody tell me what I'm doing wrong here?

import UIKit

class ConversionViewController: UIViewController {
    @IBOutlet var celsiusLabel: UILabel!
    var fahrenheitValue: Measurement<UnitTemperature>? {
        didSet {
            updateCelsiusLabel()
        }
    }
    var celsiusValue: Measurement<UnitTemperature>? {
        if let fahrenheitValue = fahrenheitValue {
            return fahrenheitValue.convert(to: .celsius)
        }else{
            return nil
        }
    }
}

Upvotes: 2

Views: 100

Answers (2)

Rob
Rob

Reputation: 437392

rmaddy described the root of the problem, that you're trying to call a mutating function on a local let constant, and that you should instead call converted to return the converted value rather than trying to mutate the existing value.

But I might suggest simplifying this further with optional chaining:

var celsiusValue: Measurement<UnitTemperature>? {
    return fahrenheitValue?.converted(to: .celsius)
}

That will automatically return nil if fahrenheitValue is nil, and otherwise will return the value of the converted(to:) call.

Upvotes: 6

rmaddy
rmaddy

Reputation: 318774

The problem is these two lines:

if let fahrenheitValue = fahrenheitValue {
    return fahrenheitValue.convert(to: .celsius)

You can't call convert(to:) on fahrenheitValue because fahrenheitValue is a constant and convert(to:) is trying to modify that constant, hence the error.

The solution is to replace convert(to:) to converted(to:). The former doesn't return anything and tries to modify the receiver. The latter creates a new measurement and returns the new value. That is what you want.

return fahrenheitValue.converted(to: .celsius)

Upvotes: 5

Related Questions