Konstanten in Swift strukturieren

Als Apple im Juni 2014 Swift vorgestellt hat war ich begeistert. In den ersten Nächten und Wochen sog ich diese Programmiersprache auf und entwickelte ein paar Demoprojekte.

Swift lässt sich sehr schön schreiben und lesen. Ein gutes Beispiel sind die Enumerations mit der dot syntax. Hier ist ein Beispiel aus der Apple-Dokumentation:

enum CompassPoint {
    case North
    case South
    case East
    case West
}

Auf einen Wert der Enumeration kann man folgender maßen zugreifen. directionToHead = CompassPoint.East oder kürzer directionToHead = .East

Konstanten

Weiter unten im Text führe ich eine effizientere dot syntax für Konstanten in Swift ein. Zunächst möchte ich aber das Thema Konstanten motivieren.

Der offensichtlichste Vorteil ist, dass bei Mehrfachbenutzung von Literalen Änderungen nur einmal zentral vorgenommen werden müssen. So werden auch Tippfehler vermieden und die Autovervollständigung erleichtert das Schreiben. Meistens werden somit globale Parameter und Textbausteine zentral verwaltet.

Ein weiterer Vorteil ist, das die Konstanten nur einmal als Symbol abgelegt werden und dann in die entsprechenden Stellen gelinkt werden. Wenn man hingegen ein Literal mehrfach erstellt und nicht eine konstante benutz werden mehrere gleiche Symbole erstellt.

Objective-C Konstanten

Konstanten waren bereits in Objective-C ein umstrittenes Thema. In den meisten Projekten habe ich die einfache Variante mit #define gesehen.

// Constants.h
#define KSegueIdentifierLogin = @"login"

Die saubere Variante ist jedoch die mit extern const.

// Constants.h
extern NSString * const KSegueIdentifierLogin;
// Constants.m
NSString * const KSegueIdentifierLogin = @"login";

Erläuterung zu den C Konstanten

Da Objective-C auf C aufbaut betrachte ich hier den ANSI C Standard.

Die Präprozessoranweisung #define ersetzt vor dem kompilieren im gesamten Quelltext den Bezeichner, im obigen Beispiel wird also KSegueIdentifierLogin durch @"login" ersetzt. Diese Variante ist jedoch nicht typsicher und bietet auch nicht die Vorteile das Symbole nur einmal erstellt werden.

Das extern Schlüsselwort gibt die Linkage des Symbols an, somit kann auf die Konstante global zugegriffen werden.

Durch das Schlüsselwort const verhindert der Compiler eine Mehrfachzuweisung.

Wenn man extern und const kombiniert hat man eine typsichere und in der Symboltabelle sauber abgelegte Konstante.

Swift Konstanten

In einem Projekt ist mir negativ aufgefallen, das es umständlich ist Konstanten immer im Quellcode auszuschreiben wenn sie den gleichen Präfix haben.

Beispiel 1

Dies hat mich an die schöne dot syntax der Enumerations erinnert. Mein Ansatz, dies bei Konstanten umzusetzen, ist eine hierarchische struct-Notation.

struct kSegueIdentifier {
    static let home = "home"
    static let login = "login"
    static let info = "info"
}

Beispiel 2

Wie in der Grafik zu erkennen ist, bietet die IDE so eine angenehme Autovervollständigung an. Wichtig ist dabei, dass das static-Schlüsselwort gesetzt wird. So muss das struct nicht erst initialisiert werden.

Solche hierarchische Strukturen lassen sich übersichtlich und beliebig verschachteln, wie im folgenden Beispiel gut zu erkennen ist:

struct kSection {
    
    struct SubSection {
        static let value1 = "value1"
        static let value2 = "value2"
        // …
        
        struct SubSubSection {
            static let value1 = "value1"
            static let value2 = "value2"
        }
        
    }
    
    struct SecondSubSection {
        static let value1 = "value1"
        static let value2 = "value2"
    }
    
}

Wenn man diese hierarchische Dot-Syntax benutzt sieht es so aus:

string = kSection.SubSection.value1
string = kSection.SubSection.value2
string = kSection.SubSection.SubSubSection.value1
string = kSection.SecondSubSection.value1
string = kOtherSection.OtherSubSection.value1
// …

Erläuterung zu den Swift Konstanten

Wenn man folgende Variante ohne static-Schlüsselwort benutzen würde

struct Section {
    let value1 = "value1"
    let value2 = "value2"
}

string = kSection.value1

muss man zuvor den struct Section wie folgt initialisieren

let kSection = Section()

Setzt man vor dem let ein static wird die Konstante zu einer Type Property. Mann kann nun direkt auf die konstante zugreifen ohne das der Struct initialisiert werden muss.