Continuing the discussion about variables in Swift, let us move on to properties, which are basically Swift constants or variables used in a class, structure, or enumeration. More specifically, they are stored values for a class, structure, or enumeration, that have getter and setter methods that can be modified. You can leave them alone, and they will do what they should (return the value or set a new one). The getters and setters can be overridden, like to override the setter to allow you to check if the input value is valid before storing it. Getters and setters are also called “accessors” and “mutators” respectively. Take your pick, but for me, I’m going to just call them getters and setters.
There are a few more aspects to properties, but today, we will be talking about a specific type of property.
Swift Computed Properties
Swift computed properties are properties that do not have their own backing store and are particularly useful for conversions. Here’s an example of a computed property. Lets say our program has a custom class that stores time. Yes, we could use DateComponents, but bear with me here to show a possible use for Swift computed properties. When we use this class, we may want to use it in seconds, minutes, hours, days, etc. We could set up methods to calculate that for us, and we would in other languages, but in Swift, we could write a class like so:
class Time { var seconds:Double = 0 init(seconds: Double) { self.seconds = seconds } var minutes: Double { get { return (seconds / 60) } set { self.seconds = (newValue * 60) } } var hours: Double { get { return (seconds / (60 * 60)) } set { self.seconds = (newValue * (60 * 60)) } } var days: Double { get { return (seconds / (60 * 60 * 24)) } set { self.seconds = (newValue * (60 * 60 * 24)) } } }
In this class, we first created a Double variable that stores “seconds.” We then created 3 computed properties for minutes, hours, and days. The getters divide the seconds by the appropriate scaling factor, and return that. The setters multiply by the appropriate scaling factor and save that in the instance variable.
One important thing to note is that computed properties must be created as variables with the var keyword. They cannot be written as constants, even if it is a read-only computed property.
For the setters in these computed properties, you probably noticed the “newValue” variable. That is the default name for whatever new value is sent to the setter. The setter for this property is actually:
set(newValue) { self.seconds = (newValue * 60) }
You can change that to whatever you want, if you want it really obvious, since this one is the one for minutes, you could do something like this:
set(newMinutes) { self.seconds = (newMinutes * 60) }
When you do not specify that input parameter to the setter, “newValue” is the one automatically generated for you. If you change it to “newMinutes” like this, “newValue” no longer is generated, and starts showing an error if you changed the input parameter name, but not the one used inside (change the “set” one, but not the “newValue * 60” one).
One thing to note, the “newValue” part is not specific to computed properties. It is also used in property observers, as well as subscripts. I’ll probably cover those in a future post. Check out my post on Swift Property Observers and Custom Subscripts in Swift for more details on those uses of newValue.
You would use this class as such:
let countdown = Time(seconds: 42.0) countdown.minutes //Reading value (Results in 0.7 minutes) countdown.hours = 1 //Setting value (Internally stored as 3,600 seconds) countdown.minutes //Reading value (Results in 60.0 minutes) countdown.seconds //Reading value (Results in 3,600 seconds)
As you can see, you just access Swift computed properties like they were a normal property via dot syntax. They just happen to not have their own storage, and in this case, all rely on the storage for the seconds property.
Conclusion
I am definitely a fan of computed properties in Swift. Could we just use a method instead? Sure, but this just seems cleaner to treat them like they were member variables when you are calling the class that holds them. While I am using them for unit conversions, there are plenty of other uses for computed properties. The example in Apple’s iBook for instance, shows it being used in a struct that defines a rectangle. In that case, it stores the origin as a point (which is another struct they make in the example), and lets you modify the “center” of the rectangle via computed properties. In that case, they just add half of the appropriate dimension to the origin (origin.y + (size.height/2), for example). Nonetheless, they have many uses, unit conversions are just an easy example.
I hope you found this article helpful. If you did, please don’t hesitate to share this post on Twitter or your social media of choice, every share helps. Of course, if you have any questions, don’t hesitate to contact me on the Contact Page, or on Twitter @CodingExplorer, and I’ll see what I can do. Thanks!