Reputation: 191
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
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
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