Optionals in Swift

Swift verlangt, dass alle Variablen und Konstanten einen Wert haben müssen. Dieser kann entweder sofort bei der Deklaration oder innerhalb einer init-Methode zugewiesen werden.

Es gibt aber Situationen, in denen einer Variable (oder Konstanten) noch kein Wert zugewiesen werden kann oder schlichtweg nicht klar ist, ob sie gültige Daten enthält. Hier helfen Optionals weiter. Die Deklaration erfolgt unter Verwendung eines ? oder eines ! und sieht folgendermaßen aus:

var name: String? // name enthält eine Zeichenkette oder nil
var age: Int! // age enthält eine ganze Zahl oder nil

Nur durch diese Deklaration als Optional können beide Variablen nil enthalten.

Was hat es nun mit dem ? und dem ! auf sich?

Eine direkte Nutzung einer mit einem ? deklarierten Variable ist nicht möglich. Vielmehr muss sie ausgepackt (unwrapped) werden. Dabei kommt if-let zur Anwendung. Es handelt sich hierbei um einen nil-Test, der mit einer Zuweisung kombiniert wird. Sollte der Ausdruck auf der rechten Seite der Zuweisung ungleich nil sein, dann wird der Wert des Optionals in der Variablen gespeichert. Dies wird als Optional Binding bezeichnet.

if let temporaereKonstante = optionaleVariable {
    // Die temporäre Konstante hat nun den 
    // ausgepackten Wert der optionalen Variable,
    // sofern sie ungleich 'nil' ist.
}

Im folgenden Beispiel wird der Name ausgegeben, sofern die optionale Variable name nicht nil ist; andernfalls wird “no value” angezeigt.

if let aName = name {
    print(aName)
} else {
    print("no value")
}

Es ist übrigens legitim, dass die Variable, der der Wert der Optional-Variablen zugewiesen werden soll, den gleichen Namen hat:

if let name = name {
    print(name)
} else {
    print("no value")
}

Auspacken erzwingen

Mit der Verwendung eines ! wird das Auspacken der optionalen Variable erzwungen (implicitly unwrapped optional). Die Verwendung von if let ist hier nicht erforderlich. Das ist freilich sehr riskant. Denn sollte sich herausstelle, dass der Ausdruck nil ist, wird die App abstürzen (runtime error). Ihr solltet Euch also hundertprozentig sicher sein, dass der Ausdruck definitiv nicht nil ist.

Optional Binding und Bedingungen

Optional Binding kann auch zusammen mit einer Bedingung verknüpft werden. So kann folgender Code

func fooManualCheck(x: Int?) {
    if x == nil || x! <= 0 {
        // Value requirements not met, do something
	return
    }

    // Do stuff with x
    x!.description
}

verkürzt werden zu:

func fooBinding(x: Int?) {
    if let x = x, x > 0 {
        // Do stuff with x
        x.description
    }
}

Hinweis: Dies ist die Syntax in Swift 3. Früher wurde hingegen where genutzt; der Code sah folgendermaßen aus:

func fooBinding(x: Int?) {
    if let x = x where x > 0 {
        // Do stuff with x
        x.description
    }
}

guard

Im Gegensatz zu if let, wird beim guard statement der Code ausgeführt, wenn die Bedingung nicht eintritt:

func fooGuard(x: Int?) {
    guard let x = x, x > 0 else {
    // Value requirements not met, do something
    return
    }
		
    // Do stuff with x
    x.description
}

Dabei kann guard auch in den Fällen verwendet werden, bei denen kein optionaler Wert vorliegt:

func fooNonOptional(x: Int) {
    guard x > 0 else {
    // Value requirements not met, do something
    return
    }
		
    // Do stuff with x
}

Nil Coalescing

Es kommt vor, dass ein Standardwert zugewiesen werden soll, sofern eine Variable gleich nil ist:

if n == nil {
    i = defaultValue
    } else {
        i = n!
    }
}

Dies lässt sich mit dem ternären Operator verkürzen zu:

i = (n == nil) ? defaultValue : n!

Und noch kürzer wird es mit dem NilCoalescing-Operator ??. Damit kann auf sehr verkürzte Weise ein Optional einer Variablen zugewiesen werden:

i = n ?? defaultValue

Wenn n nicht nil ist, wird n der Variablen i zugewiesen, andernfalls wird defaultValue zugewiesen.

Optional Chaining

Sobald mehrere optionale Werte vorliegen, kann ein optional chaining ins Spiel kommen. Dabei handelt es sich um eine Verkettung von nil-Tests und deren Auswertung. Betrachten wir dazu folgendes Beispiel:

class Politician {
    var name: String
	init(name: String) {
        self.name = name
    }
}

class GreenParty {
    var name: String
	var politician: Politician?
	init(name: String) {
	    self.name = name
	}
}

class MemberOfParliament {
    var parliament: String
    var greenParty: GreenParty?
    init(parliament: String) {
        self.parliament = parliament
    }
}

Hier habe ich drei Klassen erstellt. Die Klasse MemberOfParliament enthält den optionalen Wert greenParty. Denn womöglich ist eine entsprechende Partei gar nicht Mitglied des Parlaments.

Die Klasse GreenParty wiederum enthält den optionalen Wert politician. Das ist zugegebenermaßen etwas konstruiert, denn vermutlich wird es bei den Grünen etwaige Politiker geben.

Schließlich haben wir die Klasse Politician, die lediglich als Ausgangspunkt für ein “Politiker-Objekt” dient.

Nun initialisieren wir diese Klassen:

var germanGreenParty = GreenParty(name: "Bündnis 90 / Die Grünen")
var bundestag = MemberOfParliament(parliament: "bundestag")
bundestag.greenParty = germanGreenParty
var politician = Politician(name: "Dieter")
germanGreenParty.politician = politician

Optional Chaining erlaubt nun die optionalen Werte nach der if let-Anweisung hintereinander zu setzen.

if let name = bundestag.greenParty?.politician?.name {
    print("\(name) is a member of the Bundestag.")
} else {
    print("Cannot check the memberchip.")
}

Im Ergebnis steht uns also bei der Überprüfung mehrerer optionaler Werte — Dank Optional Chaining — eine einfache Schreibweise zur Verfügung. Außerdem ist der Code einfacher zu lesen.

Nachfolgend ein weiteres Beispiel:

Folgender Ausdruck führt zu einem Absturz der App, falls die Eigenschaft nil ist:

navigationController!.delegate = self

Mit folgendem Code kann aber ein Absturz vermieden werden, falls der als optional deklarierte navigationController keinen Wert haben sollte:

navigationController?.delegate = self

Denn das hier verwendete ? besagt: Alles nach dem Fragezeichen wird ignoriert, falls der Ausdruck nil ist. Diesen Zeile Code ist mit folgendem Code identisch:

if navigationController != nil {
    navigationController!.delegate = self
}

Auch dieses Beispiel zeigt sehr anschaulich, dass mit Optional Chaining eine verkürzte Schreibweise möglich ist.

Durch Benutzung dieser Website erklären Sie sich mit der Verwendung von Cookies einverstanden. Mehr Informationen

Die Verwendung von Cookies dient dazu, Inhalte und Anzeigen zu personalisieren, Funktionen für soziale Medien anbieten zu können und die Zugriffe auf diese Website zu analysieren. Außerdem werden Informationen zur Nutzung dieser Webseite an Partner für soziale Medien, Werbung und Analysen weitergegeben.

Schließen