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.
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"
}
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.