Kapitel 2: Grundlagen / 2.9 Optionals / 2.9.6 Implizites Unwrapping

Während das erzwungene Unwrapping unmittelbar einleuchtend ist und das Unwrapping durch Optionales Binding nach zweimaligem Hinsehen den Code verschlanken kann, ist diese dritte Variante schon ein bißchen kurios.

Beim impliziten Unwrapping eines Optionals handelt es sich genaugenommen um einen weiteren, einen dritten Typ: Neben den Basisdatentyp und der optionale Variante dieses Datentyps, gibt es als drittes die implizit unwrapped optionale Variante dieses Datentyps. Hier trete ich mir mit dem Deutsch-Englisch fast selbst auf die Füße.

Im Prinzip handelt es sich hierbei um nichts weiter als ein Optional, das nicht geunwrapped werden muss, wenn man auf seinen Wert zugreifen will. Oder man betrachtet es andersherum: Es ist ein Basisdatentyp, der hinter den Kulissen ein Optional ist, und dem man daher zur Not auch ein nil unterschieben kann.

Ich sage absichtlich zur Not, denn wenn Sie vorhaben, eine Variablen in Ihrem Programm irgendwann einmal nil werden zu lassen, dann sollten Sie ein gewöhnliches Optional verwenden. Soll diese Variable niemals nil werden, dann verwenden Sie einen Basisdatentyp. Es gibt also kein Szenario, in dem ein Implizit Unwrapped Optional nötig wäre..

Stimmt aber nicht, es gibt mindestens ein sehr technisches Szenario, in dem Apple Implizit Unwrapped Optionals verwendet, ich werde gleich noch genauer darauf eingehen. Es handelt sich hierbei aber um einen nur in wenigen Ausnahmesituationen technisch benötigten Typ, nicht um einen für die Alltagsprogrammierung.

Zunächst aber dazu, wie ein so ein Implizit Unwrapped Optional aussieht:

Um ein Implizit Unwrapped Optional zu deklarieren, setzen Sie ein Ausrufungszeichen hinter den Basisdatentyp. Sozusagen ein für allemal:

var alterString = "32"
var alterIUOptional: Int! = alterString.toInt()
var alter: Int = alterIUOptional

In der zweiten Zeile können Sie sehen, dass die Variable alterIUOptional sozusagen optional genug ist, um das Ergebnis von alterString.toInt() entgegenzunehmen. Gleichzeitig ist sie aber automatisch unwrapped, so dass bei der Zuweisung in der dritten Zeile kein Ausrufungszeichen nötig ist.

Da es sich auch bei der implizit unwrapped Variante von Optionals um Optionals handelt, können Sie auch hinter ein Implizit Unwrapped Optional ein Ausrufungszeichen setzen, so als wollten Sie es erzwungen unwrappen. Das ist zwar vollkommen überflüssig, führt aber nicht zu einem Fehler. Genauso können Sie ein Implizit Unwrapped Optional auf nil testen (mit == oder !=) oder es innerhalb des Optional Binding verwenden – was schon mehr Sinn macht.

Ein Implizit Unwrapped Optional enthält bei der Deklaration den Defaultwert nil (wenn kein Wert zugewiesen wird) oder Sie können ihm nil von Hand zuweisen. Es kann nicht das nil aus einem regulären Optional übernehmen (was etwas überraschend ist), das führt zu einer Runtime Exception. Genauso scheitert die Zuweisung an den Basistyp, wenn das Implizit Unwrapped Optional nil ist – ebenfalls mit einer Runtime Exception (was gar nicht überraschend ist).

Ändern Sie also im obenstehenden Beispielcode den String „32“ in den String „Keine Zahl“, dann knallt es gleich zweimal:

var alterString = "Keine Zahl"
var alterIUOptional: Int! = alterString.toInt()
var alter: Int = alterIUOptional

Das erste Mal in der zweiten Zeile mit dem Text: „Unexpectedly found nil while unwrapping an Optional value.“ (Beim Unwrappen eines optionalen Wertes wurde unerwartet nil gefunden.) Das nil aus dem alterString.toInt() kann also nicht übernommen werden.

Deutlicher wird das noch, wenn Sie das Optional herausschreiben:

var alterString = "Keine Zahl"
var alterOptional: Int? = alterString.toInt()
var alterIUOptional: Int! = alterOptional
var alter: Int = alterIUOptional!

Hier kommt es nun bei Ausführung der dritten Zeile zur Runtime Exception, im Moment der Zuweisung.

Ersetzen Sie von Hand das alterOptional in der dritten Zeile durch nil, weisen Sie nil also explizit zu, kann die dritte Zeile hingegen ausgefürt werden. Jetzt knallt es aber bei der Ausführung der Vierten. Die Fehlermeldung ist dieselbe, denn Sie können einem Int nicht nil zuweisen. Probieren Sie es einmal selbst aus, spielen Sie mit den verschiedenen Varianten selbst einmal herum.

Nun aber noch zu dem angekündigten technischen Szenario, in dem Implizit Unwrapped Optionals tatsächlich Sinn machen. Wenn Sie möchten, können Sie dies überlesen; es verwendet, wie früher ja schon, die Begriffe Objekt und Eigenschaft, die in einem späteren Kapitel genauer erklärt werden.

Objekte können verschiedene Eigenschaften haben. Ein Auto hat die Eigenschaft Farbe mit dem Wert Weiß. Oder eine Stadt hat die Eigenschaft Bundesland, um das Bundesland zu bezeichnen, in dem sie liegt, zum Beispiel Schleswig Holstein im Falle von Kiel. Bleiben wir bei den Städten und ihren Bundesländern.

Da jede deutsche Stadt in einem Bundesland liegt, soll die Eigenschaft Bundesland im Objekt Stadt nicht optional sein. Sobald ein Objekt Stadt existiert, soll die Eigenschaft Bundesland also immer einen Wert haben.

Umgekehrt soll es ein Objekt Bundesland geben und es soll die Eigenschaft Hauptstadt haben. Auch diese Eigenschaft ist nicht optonal, da jedes Bundesland ja eine Hauptstadt hat.

Wir haben also das Objekt Bundesland mit der Eigenschaft Hauptstadt, also einem Objekt vom Typ Stadt, und das Objekt Stadt mit der Eigenschaft Bundesland. Es entsteht, wie Sie sich denken können, so etwas ähnliches wie ein Kreis, da beispielsweise die Stadt Kiel das Bundesland Schleswig Holstein als Eigenschaft hat und das Bundesland Schleswig Holstein hat die Stadt Kiel als Eigenschaft. Die beiden Objekte Schleswig Holstein und Kiel enthalten einander gegenseitig, sie verweisen beide aufeinander.

Das ist erstmal kein Problem. Programmiertechnisch geht so etwas. Es gibt aber eine kleine Ausnahme: Wenn man ein Objekt mit nicht optionalen Eigenschaften initialisiert, also initial erzeugt, dann muss man ihm auf einen Schlag die Werte aller Eigenschaften mitgeben. Täte man das nicht, sparte man also eine Eigenschaft aus, dann wäre sie kurzzeitig nil, müsste also optional sein und das soll ja nicht sein. Entwerder das Objekt existiert also gar nicht oder es existiert mit allen Eigenschaften.

Zwei Objekte können aber leider nicht gleichzeitig erzeugt werden, sie werden immer nacheinander erzeugt. Wenn nun zwei Objekte einander enthalten, kommt es zu einem Problem: Während das zweite Objekt erzeugt wird, ist das erste schon da, das geht, aber während das erste Objekt erzeugt wird, fehlt das zweite noch. Das ist schlecht.

Eines muss zuerst erzeugt werden: Schleswig Holstein oder Kiel. Wenn Kiel zuerst erzeugt wird, dann kann es aber als Bundesland nicht das Objekt Schleswig Holstein zugewiesen bekommen, denn das existiert ja noch gar nicht. Oder eben umgekehrt.

Da sich hier die Katze in den Schwanz beisst, behilft sich Apple mit einem Implizit Unwrapped Optional: Es fühlt sich an und kann benutzt werden, als wäre es kein Optional, darf aber ganz kurz mal während der Iniitialisierungsphase nil sein. Hat ja keiner gesehen. Wenn man die Objekte später benutzt, merkt man  davon nichts (oder kaum etwas), aber die Initialisierung kann durchgeführt werden.

Die betroffenen Eigenschaften sind also nicht wirklich nicht-optional, aber fast.. Näher kommt man an die Nicht-Optionalität bei zwei Objekten, die einander gegenseitig enthalten nicht heran.

Diese Zwei-Phasen-Initialisierung ist also so eine technische Ausnahmesituation, und vielleicht die bisher einzige, in der die Verwendung von Implizit Unwrapped Optionals Sinn macht. Es ist also wirklich – wie schon erwähnt – kein Variablentyp für die Alltagsprogrammierung.

Kapitel 2.9.6: Implizites Unwrapping

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.