I've seen a lot of reasons why designing an API using variables instead of functions is problematic and to me using computed properties feels like a workaround. There are good reasons to keep your instance variables encapsulated. Here I've created a protocol Automobile that Car conforms to. This protocol has an accessor method that returns a Chassis object. Since Car conforms to it the RaceCar subclass can override it and return a different Chassis subclass. This allows the Car class to program to an interface (Automobile) and the RaceCar class that knows about RacingChassis can access the _racingChassis variable directly.
class Chassis {}
class RacingChassis: Chassis {}
protocol Automobile {
func chassis() -> Chassis
}
class Car: Automobile {
private var _chassis: Chassis
init () {
_chassis = Chassis()
}
func chassis() -> Chassis {
return _chassis
}
}
class RaceCar: Car {
private var _racingChassis: RacingChassis
override init () {
_racingChassis = RacingChassis()
super.init()
}
override func chassis() -> Chassis {
return _racingChassis
}
}
Another example of why designing an API using variables breaks down is when you have variables in a protocol. If you'd like to break out all of the protocol functions into an extensions you can, except stored properties cannot be placed in extensions and have to be defined in the class (to get this to compile you'd have to uncomment the code in AdaptableViewController class and remove the mode variable from the extension):
protocol Adaptable {
var mode: Int { get set }
func adapt()
}
class AdaptableViewController: UIViewController {
// var mode = 0
}
extension AdaptableViewController: Adaptable {
var mode = 0 // compiler error
func adapt() {
//TODO: add adapt code
}
}
The above code will have this compiler error: "Extensions may not have stored properties". Here's how you can re-write the example above so that everything in the protocol can be separated out in the extension by using functions instead:
protocol Adaptable {
func mode() -> Int
func adapt()
}
class AdaptableViewController: UIViewController {
}
extension AdaptableViewController: Adaptable {
func mode() -> Int {
return 0
}
func adapt() {
// adapt code
}
}