Swift: Public Properties With Private Setters

In Swift you can easily create public properties with private setters. It makes your code much safer and shorter.

Hint: This post has been updated to Swift 3

Encapsulation

Encapsulation means basically that information and states of a class should be hidden from outside of the class – only the class itself should manipulate it. As a consequence, both bugs and logical errors are much more unlikely.

Normally you are using setters and getters to achieve this. However, sometimes you don’t want to provide a setter outside of the class at all. For that scenario you can use properties with private setters.

Example

So imagine we want to create a class that represents a circle. It should be possible to change the radius. Furthermore, both the area and the diameter should be accessible from the Circle instance. It should not be allowed to manipulate the diameter or the area from outside of the class. For performance reasons, the area and diameter should only be calculated once.

So the class would look like this:

class Circle {
    
    private var area: Double = 0
    private var diameter: Double = 0
    
    var radius: Double {
        didSet {
            calculateFigures()
        }
    }
    
    init(radius:Double) {
        self.radius = radius
        calculateFigures()
    }
    
    private func calculateFigures() {
        area = M_PI * radius * radius
        diameter = 2 * M_PI * radius
    }
    
    func getArea() -> Double {
        return area
    }
    
    func getDiameter() -> Double {
        return diameter
    }
    
}

So all of the requirements are fulfilled. However, in Swift there is a very good way to make this even shorter:

Properties With Private Setters

By using private(set) in front of a property, a property has the default access level for the getter, but a private setter. So we can drop the two getters:

class Circle {
    
    private(set) var area: Double = 0
    private(set) var diameter: Double = 0
    
    var radius: Double {
        didSet {
            calculateFigures()
        }
    }
    
    init(radius:Double) {
        self.radius = radius
        calculateFigures()
    }
    
    private func calculateFigures() {
        area = M_PI * radius * radius
        diameter = 2 * M_PI * radius
    }
}

Of course it is also possible to have public getters for the properties:

public class Circle {
    
    public private(set) var area: Double = 0
    public private(set) var diameter: Double = 0
    
    public var radius: Double {
        didSet {
            calculateFigures()
        }
    }
    
    public init(radius:Double) {
        self.radius = radius
        calculateFigures()
    }
    
    private func calculateFigures() {
        area = M_PI * radius * radius
        diameter = 2 * M_PI * radius
    }
}

Objects

In this example the properties were just double values. However, if it is an object, it could be manipulated by using one of the object’s methods! The use of a private setter would just permit to assign a complete new object. Keep that in mind, when you are using private setters.

References

Image: @ 1000 Words / shutterstock.com
Swift: Access Control