Read-only and non-computed variable properties in Swift

Zaxonov picture Zaxonov · Jun 6, 2014 · Viewed 60k times · Source

I'm trying to figure out something with the new Apple Swift language. Let's say I used to do something like the following in Objective-C. I have readonly properties, and they cannot be individually changed. However, using a specific method, the properties are changed in a logical way.

I take the following example, a very simple clock. I would write this in Objective-C.

@interface Clock : NSObject

@property (readonly) NSUInteger hours;
@property (readonly) NSUInteger minutes;
@property (readonly) NSUInteger seconds;

- (void)incrementSeconds;

@end

@implementation Clock

- (void)incrementSeconds {
     _seconds++;

     if (_seconds == 60) {
        _seconds = 0;
        _minutes++;

         if (_minutes == 60) {
            _minutes = 0;
            _hours++;
        }
    }
}

@end

For a specific purpose, we cannot touch the seconds, minutes and hours directly, and it's only allowed to increment second by second using a method. Only this method could change the values by using the trick of the instance variables.

Since there are no such things in Swift, I'm trying to find an equivalent. If I do this:

class Clock : NSObject {

    var hours:   UInt = 0
    var minutes: UInt = 0
    var seconds: UInt = 0

    func incrementSeconds() {

        self.seconds++

        if self.seconds == 60 {

            self.seconds = 0
            self.minutes++

            if self.minutes == 60 {

                self.minutes = 0
                self.hours++
            }
        }
    }
}

That would work, but anybody could change directly the properties.

Maybe I already had a bad design in Objective-C and that's why the potential new Swift equivalent is not making sense. If not and if someone have an answer, I would be very grateful ;)

Maybe the future Access Control Mechanisms promised by Apple is the answer?

Thanks!

Answer

Ethan picture Ethan · Sep 30, 2014

Simply prefix the property declaration with private(set), like so:

public private(set) var hours:   UInt = 0
public private(set) var minutes: UInt = 0
public private(set) var seconds: UInt = 0

private keeps it local to a source file, while internal keeps it local to the module/project.

private(set) creates a read-only property, while private sets both, set and get to private.