Im vergangenen Kapitel haben Sie sich mit Xcode vertraut gemacht und ein iPhone-Projekt aus einer Vorlage erstellt und bearbeitet. In diesem Kapitel werden Sie sich mit der Programmiersprache Swift und ihren Möglichkeiten vertraut machen. Zu diesem Zweck verwenden Sie die so genannten Playgrounds. Auf Deutsch ließe sie sich mit »Spielwiese« übersetzen. Dies sind Dateien in Xcode, in denen Sie Swift-Befehle eingeben, die dann direkt ausgeführt werden. Dadurch können Sie schnell und einfach verschiedene Sachen ausprobieren.
Sie werden insbesondere Variablen und Konstanten kennenlernen und erfahren, was es mit Datentypen auf sich hat Zahlen, Texte und Wahrheitswerte. Sie werden außerdem sehen, wie Sie Anweisungen kombinieren und Bedingungen prüfen. Schließlich gebe ich Ihnen eine Sammlung von Empfehlungen, wie Sie mit Ihrem neuen Wissen umgehen sollten, wenn Sie neue Programmtexte in Swift schreiben. Am Ende dieses Kapitels werden Sie erste Programme schreiben können, die Rechenaufgaben lösen und Bedingungen verarbeiten.
Die Beispiele in diesem und in den folgenden Kapiteln verwenden keine grafische Benutzeroberfläche. Dadurch können Sie sich einfacher auf die eigentliche Programmierung konzentrieren, ohne sich gleichzeitig mit den Eigenheiten der grafischen Oberfläche auseinandersetzen zu müssen.
Um einen Playground zu erzeugen, drücken Sie in Xcode die Tastenkombination
+
+
+
. Nun wird ein neues Fenster geöffnet und Sie müssen einen Dateinamen für den Playground eingeben. Außerdem läßt sich unter PLATFORM auswählen, auf welche plattform-spezifischen Programmschnittstellen Sie zugreifen möchen hier haben Sie die Auswahl zwischen IOS und OS X. Geben Sie als Namen bitte »SuperRechner« ein und wählen Sie als PLATFORM den Eintrag IOS aus, siehe Abbildung 3.1.
Abbildung 3.1 Konfiguration des Playground »SuperRechner« in Xcode
Klicken Sie nun den Button NEXT und geben Sie einen Speicherort für den Playground an. Klicken Sie anschließend auf CREATE.
Abbildung 3.2 Der Playground direkt nach dem Erzeugen in Xcode
Der Startbildschirm des Playgrounds ist in Abbildung 3.2 zu sehen. Das Fenster ist zweigeteilt:
"Hello,
playground"
. In dieser Spalte werden die Ergebnisse der Anweisungen, die Sie in der linken Spalte schreiben, ausgegeben. Zumindest dann, wenn die Anweisungen etwas Sinnvolles erzeugen.Dieser Startbildschirm ähnelt dem »Hallo, Welt«-Projekt aus dem letzten Kapitel. Der Programmtext in der linken Spalte lautet:
// Playground -- noun: a place where people can play
import UIKit
var str = "Hello, playground"
Die drei Zeilen sind ebenfalls sehr ähnlich zu dem, was Sie bereits kennen:
//
eingeleitet. Hierbei handelt es sich wieder um eine Kommentarzeile.let
, sondern das Wort var
verwendet. Das Wort var
erzeugt keine Konstante, sondern eine
Variable. Diese funktioniert ähnlich wie eine Konstante, kann ihren Wert jedoch noch ändern. In diesem Fall weisen Sie str
als Wert die Zeichenkette »Hello, playground
« zu (ohne Anführungszeichen).Abbildung 3.3 Drei Konstanten mit der Addition zweier Zahlen im Playground »SuperRechner«
Geben Sie darunter nun die drei Zeilen ein, die Sie bereits aus Listing 2.2 von kennen:
let aepfel = 34
let birnen = 67
let allesObst = aepfel + birnen
Das Ergebnis sehen Sie in Abbildung 3.3. In der rechten Spalte finden sich als »Ergebnisse« der Anweisungen jeweils die Werte der Konstanten. Für aepfel
und birnen
ist das nicht so interessant (dafür brauchen Sie keinen Computer), aber für allesObst
sieht das schon anders aus: hier erfahren Sie direkt, was das Ergebnis der Addition ist nämlich 101. Das ist schon viel interessanter!
Sie haben jetzt gesehen, dass Sie eine Konstante definieren und ihr einen Wert zuweisen dürfen. Ebenso läßt sich eine Variable definieren. Ich möchte den Unterschied an dieser Stelle noch etwas verdeutlichen.
Versuchen Sie einmal, die folgenden Zeilen einzugeben. Zunächst einmal
str = "Hallo, Spielwiese"
Das Ergebnis ist, dass in der rechten Spalte nun "Hallo, Spielwiese"
ausgegeben wird. Dies bedeutet nichts anderes, als dass Sie der Variablen str
einen neuen Wert gegeben haben. Der alte Wert war ein englischer Text, der neue Wert ist die deutsche Übersetzung davon.
Nun versuchen Sie einmal, die nächste Zeile einzugeben:
aepfel = 30
Nun erscheint links neben dem Programmtext ein rotes Ausrufezeichen und wenn Sie darauf klicken, erscheint die Fehlermeldung Cannot assign to ’let’ value ’aepfel’. Dies weist darauf hin, dass Ihr Mac den Wert von aepfel
nicht ändern kann, weil sie ihn mit let
und nicht mit var
erzeugt haben.
Das läßt sich auch nachprüfen: verändern Sie einmal in der Zeile, die mit let aepfel
beginnt, das let
zu einem var
, siehe Abbildung 3.4. Was ist nun mit dem Fehler passiert?
Abbildung 3.4 Korrektur eines Fehlers im Playground
Ja, genau! Die Fehlermeldung in der Zeile mit aepfel = 30
ist in der Tat verschwunden! Dadurch sind Playgrounds so richtig nützlich, denn sie helfen Ihnen dabei, schnell die Auswirkungen von Änderungen auf alle folgenden Zeilen zu sehen. Wenn Ihre Programme später komplizierter werden, so werden Sie die Möglichkeiten von Playgrounds immer mehr zu schätzen wissen!
Der wesentliche Unterschied zwischen let
(Definition einer Konstanten) und var
(Definition einer Variablen) ist somit, dass Sie Konstanten nicht mehr ändern dürfen, Variablen hingegen schon. Das geht sogar beliebig oft, solange das Programm läuft. Es ist also völlig in Ordnung, wenn Sie ein Programm schreiben, das aepfel
zunächst den einen, später einen anderen und dann noch einen weiteren Wert gibt.
In der Praxis sieht das so aus: Zu einem späteren Zeitpunkt in Ihrem Programm schreiben Sie
aepfel = 10
wenn Sie beispielsweise 24 Äpfel gegessen haben, also nur noch 10 übrig sind. Dabei wird zunächst die rechte Seite neben dem =
-Zeichen ausgewertet, also die Zahl 10. Diese wird dann anschließend der Variablen aepfel
zugewiesen. Der alte Wert wird dann verworfen und Ihr Mac »vergisst« ihn. Wenn Sie ab dieser Stelle auf die Variable aepfel
zugreifen, dann ist ihr Wert 10 und eine neue Berechnung von allesObst
benutzt den neuen Wert (beachten Sie, dass Sie dafür ebenfalls allesObst
mit var
definieren müssen):
var aepfel = 34
var birnen = 67
var allesObst = aepfel + birnen
// Jetzt ist allesObst = 101.
// Ändern des Wertes.
aepfel = 10
// Jetzt ist aepfel = 10, aber allesObst immer noch 101.
allesObst = aepfel + birnen
// Jetzt ist aepfel = 10 und allesObst 77.
Die aktuellen Werte lassen sich auch immer in der rechten Spalte des Playgrounds kontrollieren. Alternativ schreiben Sie die Variable einfach direkt in eine Zeile. So gibt die Zeile
allesObst
beispielsweise in der rechten Spalte den aktuellen Wert von allesObst
direkt aus, ohne ihn zu ändern.
Einen weiteren Vorteil haben Sie: In Swift lassen sich Konstanten und Variablen sehr kreativ benennen: Sie dürfen kleine und große Buchstaben verwenden, Umlaute und sogar Zeichen aus anderen Sprachen. In der Mitte sind auch Ziffern und Zahlen erlaubt und Namen dürfen auch lang sein. Leerzeichen dürfen allerdings nicht vorkommen. Alle Beispiele in Listing 3.1 sind erlaubte Variablennamen.
Swift ist bei der Benennung extrem flexibel und großzügig. Kaum eine andere Sprache bietet die Möglichkeit, beliebige Sonderzeichen zu verwenden.
Das hat den Vorteil, dass Sie in Swift alle Ihre Variablen beliebig benennen dürfen. Und es hat den Nachteil, dass Sie in Swift alle Ihre Variablen beliebig benennen dürfen. Sie können Deutsch mit Umlauten verwenden. Oder Russisch mit kyrillischen Schriftzeichen. Oder traditionelles Chinesisch. Oder einen Mischmasch aus Smileys.
_
.a
x
dasAlterVonSteve
einahmenDesBankDirektorsImJahr2007
diesIstEinSuperDuperErgebnis
dasVerflixte7bteJahr
fürUndWider
Listing 3.1 Beispiele für erlaubte Variablennamen in Swift
In Listing 3.2 sind weitere Beispiele dafür gezeigt, wie Sie Variablen neue Werte geben. Beachten Sie, dass Sie dafür vorher für jede Variable einmal eine Zeile der Form
var a = 0
benötigen, damit Swift weiß, dass es sich dabei um eine Variable handelt, mit der Sie arbeiten wollen (und nicht um einen Schreibfehler).
Wie Sie sehen, ist es auch erlaubt, a = a + 1
zu schreiben, denn es wird zunächst die rechte Seite ausgewertet (der bisherige Wert von a
plus die Zahl 1) und dann das Ergebnis der Variablen a
zugewiesen. Umgangssprachlich ausgedrückt bedeutet
a = a + 1
also: »Erhöhe den Wert der Variablen a
um eins.«
// Einfache Berechnung mit zwei Zahlen.
a = 27 / 3
// Berechnung aufgrund von zwei anderen Variablen.
gutHaben = rate * jahre
// Kompliziertere Berechnung mit Zahlen und einer anderen Variablen.
meinErgebnis = 35 + (12 + 42 * 2 -- 24) / b
// Erhöhe den Wert von a um 1.
a = a + 1
Listing 3.2 Beispiele, wie Variablen neue Werte zugewiesen werden
Beachten Sie außerdem, dass Ihr Mac die »Punkt vor Strich«-Regel sowie Klammerungen beherrscht der Ausdruck »12 + 42 * 2 24« bedeutet also »Multipliziere 42 mit 2, addiere 12 und subtrahiere 24«. Das Ergebnis ist 72.
Die Zuweisung »Erhöhe den Wert um eins« ist eine in der Praxis recht häufige Anwendung, sodass es für diesen Fall sogar einen eigenen Begriff namens Inkrementieren und eine ganz spezielle Schreibweise gibt:
a += 3
Diese Anweisung ist identisch mit
a = a + 3
Sie haben jetzt Variablen kennengelernt und können deren Werte verändern. Probieren Sie nun einmal folgenden Zeilen im Playground aus:
var schulNote1 = "Sehr gut"
schulNote1 = 1
Die erste Zeile definiert, wie gehabt, eine Variable mit Namen schuleNote
und weist ihr eine Zeichenkette (auf Englisch String) zu. Das haben Sie bereits in Abschnitt 3.1 kennengelernt. Die zweite Zeile weist der Variablen einen neuen Wert zu, auch das kennen Sie bereits.
Allerdings erzeugt die zweite Zeile einen Fehler zu erkennen an dem roten Ausrufungszeichen in Xcode. Der Fehler ist in Abbildung 3.5 zu sehen und diesmal ist die Beschreibung »Type >String< does not conform to protocol >IntegerLiteralConvertible<« absolut verwirrend und nutzlos. Was läuft denn hier schief?
Abbildung 3.5 Fehlermeldung von Xcode beim Versuch, einer Variable einen neuen Wert zuzuweisen
Um den Grund zu verstehen, aus dem Xcode sich beschwert, müssen Sie sich etwas genauer anschauen, was die erste Zeile genau bewirkt. Sie tut nämlich die folgenden drei Dinge:
schuleNote1
. Dadurch dürfen Sie ab dieser Stelle mit schulNote1
die Variable benutzen.
Wenn die Variable jetzt an späterer Stelle einen anderen Wert bekommen soll, so »erinnert« sich Ihr Mac daran, dass er Speicherplatz für einen String bereitgestellt hat. Dementsprechend muss ein neuer Wert ebenfalls ein String sein. Eine Zahl geht da gar nicht.
Das ist ein wichtiger Grundsatz von Variablen: Die speichern nur eine bestimmte Art von Daten und Ihr Computer hat in Swift eine Null-Toleranz-Politik: Ihre Entscheidung lässt sich später nicht mehr ändern es gilt »einmal ein String, immer ein String«. Die Art von Daten nennt man auch den Datentyp.
Bisher hat Swift selbstständig entschieden, welchen Datentyp eine Konstante oder eine Variable haben soll. Das ist dadurch geschehen, dass Sie ihr direkt einen Wert zugewiesen haben. In Swift dürfen Sie aber auch ausdrücklich selbst entscheiden, welchen Datentyp Sie haben wollen. Und dafür brauchen Sie auch nicht unbedingt einen Wert angeben.
Wenn Sie wissen, dass eine Variable eine Zahl enthalten soll, so schreiben Sie Folgendes:
var schulNote3:String
Diese Zeile definiert wie gehabt eine Variable schulNote3
. Allerdings geben Sie keinen Wert an, sondern Sie schreiben hinter den Namen :String
, was so viel bedeutet wie »diese Variable hat als Datentyp String«, d.h. sie ist zur Speicherung von Zeichenketten gedacht.
Anschließend schreiben Sie dann problemlos:
schulNote3 = "Befriedigend"
und vergeben so neue Werte. Wenn Sie einen Datentyp festlegen, so spricht man auch von einer Deklaration.
Eine Frage ist aber noch offen: Wenn Sie die Variable nur deklarieren, aber ihr noch keinen Wert zuweisen, welchen Wert hat sie denn dann? Die naheliegende (und auch korrekte) Antwort lautet: der Wert ist noch unbekannt. Für »unbekannt« haben Informatiker einen eigenen Begriff: undefiniert. Und wenn es schon ein eigenes Wort für »unbekannt« gibt, dann liefern Informatiker gleich noch ein weiteres Wort für »vorstellen« nach: Wenn Sie einer »undefinierten« Variablen das erste Mal einen Wert zuweisen, so initialisieren Sie die Variable.
Strings, also Zeichenketten, kennen Sie bereits: Ein String wird von doppelten Anführungszeichen begonnen und damit auch wieder beendet. Innerhalb der beiden doppelten Anführungszeichen darf dann ein (fast) beliebiger Text stehen. Die folgenden Zeichenketten sind Beispiele für einwandfreie Swift-Strings: "Gehen Sie geradeaus, dann links und fragen Sie dann jemand anders."
"
"
"Das Ergebnis von 34 + 67 ist gleich 13."
Die letzte Zeile ist zwar ein gültiger String, aber leider inhaltlich nicht richtig. Das stört den Computer aber nicht, denn ihn kümmert nur, ob die äußere Form stimmt, nicht, ob die Aussage richtig oder falsch ist. Zumindest was Strings angeht, erscheint er also ein wenig oberflächlich und achtet nicht so sehr auf die inneren Werte.
Wie Sie sehen, ist es auch möglich, beliebige Zeichen in Strings zu speichern und damit Ihre Programme in beliebige Sprachen zu übersetzen. Dies ist eine sehr bequeme Sache, denn die Apple-Ingenieure haben Ihnen dadurch sehr viel Arbeit abgenommen, die Sie sonst erledigen müssten, um Ihre Programme auf anderen Systemen auch nur zum Laufen zu bekommen.
Sie haben bereits Zahlen kennengelernt, allerdings mit einer gewissen Einschränkung. Geben Sie einmal Folgendes ein:
5/2
und schauen Sie sich das Ergebnis auf der rechten Seite an ja, genau: Das Ergebnis ist 2. Nicht etwa 2,5. Wie kommt das?
In Swift macht Xcode mit Zahlen das Gleiche wie mit Variablen. Xcode versucht zu erraten, welchen Datentyp Sie gemeint haben. Und bei Ziffernfolgen wählt er als Datentyp immer so genannte Ganzzahlen (auf Englisch Integer) aus.
Und wenn Sie mit Ganzzahlen 5 durch 2 dividieren, erhalten Sie 2. Aber in der Schule wurden Sie ja nicht nur mit Ganzzahlen, sondern auch mit Komma und anderen Sachen geärgert. Die gute Nachricht ist, dass Sie jetzt den Spieß umdrehen und Ihrem Computer alle die Rechenaufgaben aufbürden können, die Sie damals schon gehasst haben der Computer kann nämlich auch mit Nachkommastellen rechnen. Dazu geben Sie einfach Folgendes ein:
5.0/2
Und jetzt erscheint auf der rechten Seite auch korrekt 2.5. Denken Sie bitte daran, dass Swift sich an die englischsprachige Konvention hält, als Dezimaltrenner einen Punkt und kein Komma zu verwenden. Das heißt, Sie schreiben 5.0 anstatt 5,0 und erhalten 2.5 anstatt 2,5.
Zahlen mit Nachkommastellen werden Fließkommazahlen (auf Englisch Floating point numbers oder abgekürzt Floats genannt). Es gibt sogar zwei verschiedene Arten: zum einen Float und zum anderen Double, was eine Abkürzung von Double precision numbers ist, also Fließkommazahlen mit doppelter Genauigkeit entspricht.
Genauso wie Sie bei Variablen ausdrücklich auswählen konnten, dass Sie es mit String
s zu tun haben wollen, dürfen Sie auch angeben, wenn Sie mit Float
oder Double
arbeiten wollen:
// Definition einer Variablen vom Typ Float.
var meineFliesskommaZahl:Float
// Definition einer Variablen vom Typ Double.
var meineSehrGenaueZahl:Double
Auf diesem Wege deklarieren Sie meineFliesskommaZahl
als normalen Float und meineSehrGenaueZahl
als doppelt genaue Zahl.
Double
zu verwenden.// Variable mit dem Startkapital.
var Kapital:Double = 100.0
// Das Kapital nach einem Jahr.
Kapital += Kapital * 0.05
// Das Kapital nach zwei Jahren.
Kapital += Kapital * 0.05
// Das Kapital nach drei Jahren.
Kapital += Kapital * 0.05
Listing 3.3 Kapital von 100 Euro bei einem Zinssatz von 5% nach 3 Jahren
Mit Fließkommazahlen rechnen Sie genau so, wie Sie es bereits kennen, beispielsweise bei der Berechnung von Zins und Zinseszins auf einem Bankkonto. Dies funktioniert folgendermaßen: Am Ende eines Jahres bekommen Sie auf Ihr aktuelles Guthaben Zinsen ausgezahlt im folgenden Beispiel gehe ich von 5 Prozent Zinsen aus. Am Ende des ersten Jahres haben Sie 100 Euro gespart, somit bekommen Sie 5 Prozent Zinsen dazu. Bei 100 Euro sind 5 Prozent genau 5 Euro, sodass Sie am Anfang des zweiten Jahres ein Guthaben von 105 Euro besitzen.
Am Endes des zweiten Jahres bekommen Sie dann wieder 5 Prozent, allerdings diesmal auf die 105 Euro. Das sind 5.25 Euro, womit Sie am Ende des zweiten Jahres 110.25 Euro besitzen. Und so weiter. Hier kann Ihr Mac so richtig glänzen, denn diese Aufgabe besteht nur im Anwenden einer einfachen Vorschrift. Um Zinsen und Zinseszinsen nach drei Jahren zu bereichnen, verwenden Sie den Programmtext, der in Listing 3.3 gezeigt ist. Das Ergebnis nach der dritten Zeile lautet 115.7625.
Beachten Sie bei diesem Beispiel, dass Sie eine identische Programmzeile wirklich dreimal hintereinander wiederholen und der Variablen Kapital
jedesmal ein neuer Wert zugewiesen wird! In der rechten Spalte können Sie verfolgen, wie sich der Wert von Kapital
nach jeder Zeile ändert, siehe auch Abbildung 3.6.
Abbildung 3.6 Xcode bei der Berechnung des Kapitals aus Listing 3.3
Sie kennen jetzt bereits die ganze Wahrheit über Zahlen. Zumindest wissen Sie, was in Ihrem Computer vorgeht, wenn er mit Zahlen arbeitet. Es gibt aber noch einen extrem nützlichen und wichtigen Datentyp, den Sie in vielen Ihrer späteren Programmen verwenden werden. Er wirkt allerdings auf den ersten Blick ein wenig unscheinbar.
Dieser Datentyp nennt sich Boolean, geschrieben als Bool
, und er repräsentiert entweder »Richtig« oder »Falsch«. Computer zeichnen sich generell durch ein ausgeprägtes Schwarz-Weiß-Denken aus sie kennen kein »Vielleicht«, sondern nur ein klares »Ja« (auf Englisch und in Swift true
genannt) oder ein klares »Nein« (Englisch und Swift false
). Und genau dies wird durch eine Boolean-Variable dargestellt.
// Das Alter von Steve.
var alterSteve = 25
// Das Alter von Woz.
var alterWoz = 23
// Entscheidung: Ist Steve älter?
var steveIstAelter = alterSteve > alterWoz
// Wenn ja, Ausgabe.
if steveIstAelter {
print("Steve ist älter.")
}
Listing 3.4 Verwendung einer »Bool«-Variablen für Junggebliebene
Sehen Sie sich mal Listing 3.4 an. Es erzeugt zwei Variablen alterSteve
und alterWoz
. Die erste erhält den Wert 25, die zweite den Wert 23. Dann wird eine dritte Variable erzeugt. Dieser wird ebenfalls ein Wert zugewiesen, allerdings lautet der Wert
alterSteve > alterWoz
Der Wert ist also ein Vergleich der Form »ist alterSteve
größer als alterWoz
«. Das Ergebnis ist ein Bool
. Er ist true
, da alterSteve
mit 25 tatsächlich größer ist als alterWoz
mit 23, siehe auch Abbildung 3.7.
Abbildung 3.7 Xcode bei der Auswertung der Variablen aus Listing 3.4
Am Ende enthält Listing 3.4 eine Anweisung, die Sie noch nicht kennengelernt haben: eine Bedingungsanweisung namens if
. Diese Anweisung wertet eine Bool
-Variable aus und führt den Programmtext innerhalb der geschweiften Klammern aus, falls der Wert true
ist. Andernfalls passiert nichts.
Innerhalb der geschweiften Klammern steht eine Anweisung namens print
. Diese Anweisung gibt einen Text aus, der in einem Playground in Xcode in der rechten Spalte angezeigt wird. Dabei handelt es sich um eine so genannte Funktion. Eine solche Funktion hat ähnlich wie eine Variable einen Namen, dann folgen runde Klammern, in denen Variablen oder Konstanten stehen. Wie Sie Funktionen selber definieren und was diese sonst noch können, werde ich ausführlich in Abschnitt 4.2 besprechen. Weiterhin werden Sie in Abschnitt 8.2.1 sehen, dass die print
-Funktion noch sehr viel mehr kann, als nur einfache Texte auszugeben.
Die if
-Anweisung braucht nicht unbedingt eine Variable, sondern sie kann auch direkt Bedingungen auswerten, z.B.
if alterSteve > alterWoz {
print("Steve ist älter.")
}
Grafisch lässt sich das Listing wie in Abbildung 3.8 gezeigt darstellen. Fangen Sie dafür bei dem schwarzen Punkt mit der Bezeichnung START an. Stellen Sie sich ein kleines Männchen vor, das an den Pfeilen entlangläuft und bei jedem Kasten eine Aktion ausführt. Eine Entscheidung wird durch die Raute dargestellt, das heißt, an diesen Stellen kann das Männchen entweder den einen oder den anderen Weg nehmen. Das Programm ist an dem Punkt mit der Beschriftung »Ende« beendet. Auf diesem Wege können Sie zum einen selbst nachvollziehen, was das Programm macht, und zum anderen auch Ihren Kollegen erklären, was Sie sich ausgedacht haben.
Abbildung 3.8 Entscheidung aus Listing 3.4 in grafischer Darstellung
Diese Art von Diagrammen nennt sich UML-Aktivitätsdiagramm, wobei UML für den englischen Begriff Universal Modeling Language steht, also eine universelle Sprache, um Modelle grafisch darzustellen. Ich werde UML-Diagramme noch an anderen Stellen in diesem Buch verwenden. Sie sind dafür gedacht, komplizierte Sachverhalte einfach und oft auch vereinfacht darzustellen. So hat der Programmtext in Listing 3.4 auch Anweisungen enthalten, die Variablen definiert und berechnet haben. Diese fehlen aber im UML-Diagramm, weil sie für den eigentlich wichtigen Teil nämlich die Entscheidung, ob die Nachricht »Steve ist älter« ausgegeben werden soll oder nicht nicht wichtig sind.
Denken Sie immer daran, dass Diagramme nicht für den Computer gedacht sind (der spricht sowieso nur seine eigene Maschinensprache und wir brauchen extra einen Compiler, nur um ihm Swift schmackhaft zu machen), sondern für Menschen, die Programme verstehen sollen.
Welche Möglichkeiten gibt es nun für Vergleiche von Zahlen? Sie haben bereits den Vergleich »ist größer als« kennengelernt, analog dazu gibt es natürlich auch die Umkehrung »ist kleiner als«. Auf Gleichheit testen Sie, indem Sie ==
schreiben, das heißt zwei Gleichheitszeichen hintereinander.
Dies ist zugegebenermaßen etwas seltsam, hat aber einen wichtigen Grund: Ein einzelnes Gleichheitszeichen wird ja bereits für die Zuweisung verwendet, weswegen man für den Vergleich etwas anderes verwenden muss. In Swift verwendet man daher zu diesem Zweck das doppelte Gleichheitszeichen ==
. Später werden Sie sehen, dass Swift ebenfalls das dreifache Gleichheitszeichen ===
für Vergleiche verwendet.
=
-Zeichen und für Vergleiche das doppelte
==
-Zeichen zu verwenden, gibt es auch in anderen Programmiersprachen wie Objective-C, C, C++
und Python.
===
als auch ==
(mit einer leicht unterschiedlichen Bedeutung). Die Sprache Ada benutzt für Zuweisungen an Variablen :=
. Leider gibt es hier keine einheitlichen Konventionen. Listing 3.5 zeigt, wie dieser Vergleich benutzt wird. Fügen Sie den Programmtext unterhalb Listing 3.4 ein.
// Eine Variable, die das Ergebnis des Vergleiches enthält.
var gleichAlt = alterSteve == alterWoz
// Ausgabe nur, wenn gleichAlt true ist.
if gleichAlt {
print("Steve und Woz sind beide gleich alt.")
}
Listing 3.5 Eine »Bool«-Variable für Gleichaltrige
Ändern Sie oberhalb der Vergleiche einmal die Variablen alterSteve
und alterWoz
. Wenn Sie ein größeres Alter für Steve eingeben, so erscheint wie gehabt
Steve ist älter.
Wenn Sie aber zweimal die gleiche Zahl eingeben, so erscheint
Steve und Woz sind beide gleich alt.
Alle möglichen Vergleiche zwischen Zahlen sind in Tabelle 3.1 zusammengefasst.
Vergleich | Bedeutung | Beispiel |
< | Kleiner als | geld < mehr_geld |
> | Größer als | mehr_geld > geld |
== | Ist gleich | winter_berlin == sommer_kiel |
!= | Ist ungleich | foo23 != x |
>= | Größer als oder gleich | 23 >= 23 |
<= | Kleiner als oder gleich | 12 <= 50 |
Tabelle 3.1 Vergleiche zwischen zwei Zahlen, die einen »Bool «als Ergebnis haben
==
prüft, ob zwei Zahlen exakt gleich sind. Bei Fließkommazahlen kann es aber passieren, dass sie sich nur ganz wenig unterscheiden. Deswegen sollten Sie für Fließkommazahlen ==
vermeiden.Sie erhalten Bool
-Werte nicht nur durch Vergleiche, sondern Sie können diese auch miteinander verknüpfen. Dafür gibt es die Operationen &&
und ||
. Diese sehen zugegebenermaßen etwas kryptisch aus, aber sie erlauben es, komplizierte Sachverhalte sehr kurz auszudrücken.
&&
bedeutet und, das heißt, (a && b)
ist dann true
, wenn beide Werte a
und b
true
sind.||
bedeutet oder und ist dann true
, wenn entweder a
oder b
(oder auch beide gleichzeitig) true
sind.!
. Dies bedeutet nicht, und es wird immer dann benutzt, wenn ein Bool
-Wert umgekehrt werden soll.Zum Beispiel sind die folgenden Vergleiche identisch:
a <= b
ist identisch mit (a < b) || (a == b)
.a > b
ist identisch mit (a >= b) && (a != b)
.a <= b
ist identisch mit !(a > b)
.!(a == b)
ist identisch mit (a != b)
.a == b
ist identisch mit (!(a < b) && !(a > b))
.(a < b)
und (a==b)
in (a < b) || (a==b)
sind übrigens nicht notwendig, erhöhen aber die Lesbarkeit für uns Menschen. Ich empfehle Ihnen, im Zweifelsfall eher mehr als weniger Klammern zu setzen, um deutlich zu machen, wie ein Ausdruck genau gemeint ist. Diese Vergleiche lassen sich anschließend in if
-Anweisungen benutzen, um komplizierte Sachverhalte auszudrücken. Zum Beispiel gibt ein Online-Shop einen Rabatt von 10 Cent für den 1000. Kunden, der über 60 Jahre oder unter 25 Jahre alt ist. Dies tut die folgende if
-Abfrage:
let bekommtRabatt = ((kundenZahl == 1000) &&
((kundenAlter < 25) || (kundenAlter > 60)))
// Rabatt abziehen, wenn bekommtRabatt true ist.
if bekommtRabatt {
gesamtPreis = gesamtPreis -- 0.10
}
Auf diesem Wege lassen sich auch komplizierte Bedingungen und Zusammenhänge in Ihrem Programm zusammensetzen. if
-Anweisungen gehören zu den nützlichsten und wichtigsten Dingen überhaupt und in jedem Programm gibt es in der Regel eine Menge davon.
Im Folgenden möchte ich ein paar allgemeine Empfehlungen geben, wie Sie Ihre Programmtexte verbessern, um sie einfacher verständlich und übersichtlicher zu machen. Zum einen ist dies wichtig für andere Entwickler. Es wird früher oder später passieren, dass Sie in einem Team arbeiten, und dann müssen Sie in der Lage sein, den Programmtext Ihrer Kollegen zu verstehen. Wenn Ihre Kollegen gute und lesbare Programme geschrieben haben, so wird es Ihnen sehr leicht fallen, diese zu verstehen und auch deren Arbeit weiterzuentwickeln. Sind die Programme allerdings weniger gut gelungen, so haben Sie mehr Arbeit und vor allem auch mehr Stress.
Lesbare Programme sind aber auch sehr wichtig für Sie selbst. Auch wenn Ihre Kollegen Ihnen egal sind, dann denken Sie daran, dass Sie heute ein Programm schreiben und vielleicht in drei Monaten Ihre Arbeit nochmals inspizieren möchten. Dann werden Sie sich kaum noch an alles erinnern, was Sie damals warum gemacht haben. In diesem Fall werden Sie sich wünschen, dass Sie sich mehr Mühe gegeben hätten. Lesbare und verständliche Programmtexte sind also nicht nur für andere, sondern auch für Sie ein unerlässliches Werkzeug.
Sie haben bereits Kommentarzeilen kennengelernt, nämlich die Zeilen, die durch zwei Querstriche //
eingeleitet werden und die Einstiegspunkte markiert haben, an denen Sie eigenen Programmtext einfügen. Kommentare dienen hauptsächlich dazu, bestimmte Stellen für Menschen lesbarer und verständlicher zu machen. Das macht sie zu einem wesentlichen Bestandteil des Werkzeugkastens eines jeden Programmierers.
Was aber ist ein guter Kommentar und was ein schlechter? Nicht jeder Kommentar ist ein guter Kommentar. Denn eine große Menge an Texten kann dazu führen, dass niemand mehr Lust hat, diese zu lesen.
Folgende Regeln haben sich für Kommentare bewährt:
alter
muss größer null sein«), so sollten Sie diese ebenfalls in einen Kommentar schreiben.TODO
(Englisch für »noch zu erledigen«) eingebürgert. So markieren Sie beispielsweise eine Baustelle mittels
// TODO: Fall behandeln, falls alterWoz größer als alterSteve ist.
FIXME
(Englisch für »repariere mich«). Dies ist für Fälle gedacht, die schwerwiegender als »TODO« sind, wenn beispielsweise ein Fehler entdeckt worden ist, der Probleme bereiten könnte.
// MARK:
eingeleitet wird. Hinter den Doppelpunkt :
schreiben Sie Ihren eigenen Text, der den folgenden Bereich der Datei markiert. Im Zusammenhang mit Funktionen (die in Abschnitt 4.2 ausführlich besprochen werden) können Sie beispielsweise alle Funktionen, die mit Anwenderdaten zu tun haben, gruppieren, indem Sie vor die erste Funktion schreiben:
// MARK: Anwenderdaten bearbeiten Anfang
und hinter die letzte schreiben:
// MARK: Anwenderdaten bearbeiten Ende
/// Hier ist eine Funktionsbeschreibung
Zusätzlich können Sie dann auch einige fortgeschrittene Formatierungen verwenden, die als Restructured Text bezeichnet werden. Diese Formatierungen gehen über dieses Buch hinaus, Sie können eine nähere Beschreibung beispielsweise auf dieser Seite finden (die allerdings englischsprachig ist): http://docutils.sourceforge.net/docs/ user/rst/quickref.html
Ich gebe Ihnen mal einige Beispiele für schlechte und für gute Kommentare. Listing 3.6 enthält einige Beispiele für schlechte oder zumindest weniger gute Kommentare.
// Addiere 2 zu kontostand.
kontostand = kontostand + 2
// Nehme eine Neuberechnung der Zinsen vor.
// Schreibe das Ergebnis in die Variable "zinsen".
// Verwirf dabei den alten Wert und überschreibe ihn mit
// dem neuen Wert, der dadurch berechnet wird, dass man
// den aktuell gültigen Wert des Kontostandes mit dem
// Zinssatz multipliziert.
zinsen = kontostand * zinssatz
// Schlüssel.
var pkcs12Data:CFDataRef = ldData()
var eg:UnsafeMutablePointer<CFArray?> = prBuf()
var cf = [CRYPT_PASS : String(kSecImportExportPassphrase)]
SecPKCS12Import(pkcs12Data , cf, eg)
Listing 3.6 Beispiele für weniger gelungene Kommentare
Der erste Kommentar beschreibt schlicht und ergreifend, was die folgende Programmzeile macht. Er ist zwar kurz, aber auch völlig nichtssagend, denn er gibt keine zusätzlichen Informationen als das, was in der nächsten Zeile in Swift geschrieben steht.
Der nächste Kommentar ist sehr ausführlich, aber er braucht sehr viele Zeilen Text, um etwas relativ Einfaches und Offensichtliches zu beschreiben. Durch das Lesen der Zeile Programmtext, die folgt, ist eigentlich völlig ersichtlich, was passiert, und der Kommentar bietet überhaupt keinen Mehrwert.
Der letzte Kommentar hat genau das gegenteilige Problem: Es ist völlig unklar, was die folgenden Zeilen eigentlich tun, zumal sie auch sehr kryptisch und kompliziert geschrieben sind. Und der Kommentar hilft überhaupt nicht dabei zu verstehen, was eigentlich vor sich geht.
Was läßt sich hier besser machen? Nun, der erste Kommentar in Listing 3.6 sollte gestrichen werden. Oder man schreibt, warum denn 2 zum Kontostand addiert werden soll.
Der zweite Kommentar sollte folgendermaßen umgeschrieben werden, um sinnvolle zusätzliche Informationen zu liefern:
// Berechne die Zinsen neu.
// Annahme: kontostand > 0.
// TODO: Baue eine Sicherheitsabfrage ein.
Dadurch erhalten Sie beim Lesen wichtige Zusatzinformationen, die Sie sonst vielleicht nicht erfahren hätten. Beispielsweise ist die Annahme, dass diese Zeile die Bedingung kontostand > 0
erwartet, nicht so ohne Weiteres ersichtlich. Später liesse sich noch eine Zusatzabfrage einbauen, die sicherstellt, dass dieser Code wirklich nur dann aufgerufen wird, wenn diese Bedingung erfüllt ist. Aber im Moment ist sie noch nicht da, sei es aus Zeit- oder anderen Gründen.
Die Verwendung von TODO
hat in jedem Fall den Vorteil, dass Sie jederzeit Ihren Programmtext nach dem Wort TODO
durchsuchen können und alle Baustellen finden, an denen Sie später noch refaktorieren, vereinfachen oder zusätzliche Funktionen einbauen wollen. Einen solchen Kommentar einzugeben, dauert nur wenige Sekunden. Nach ein paar Tagen alle Stellen ohne diesen Kommentar wiederzufinden, die Sie nochmals bearbeiten wollen, dauert wesentlich länger!
Der dritte Kommentar beschreibt einen Codeblock, der durchaus in realem Programmtext vorkommen könnte, aber über dieses Buch hinausgeht. Die meisten Swift-Programmierer werden diese Zeilen auf Anhieb nicht verstehen und müssten erstmal einige Zeit nachforschen, um ihn nachzuvollziehen. Was er tut, kann beispielsweise in folgendem Kommentar erklärt werden:
// Importiere vertrauliche Schlüsseldaten aus dem Zertifikat
// pkcs12Data. Falls ein Passwort benötigt wird, muss dieses in
// CRYPT_PASS enthalten sein.
// Die Schlüsseldaten stehen anschließend in eg.
// FIXME: Fehler werden nicht korrekt behandelt!
//
// Der Teil mit cf und eg ist notwendig, um die Funktion
// SecPKCS12Import aus Swift korrekt aufzurufen.
Auf diesem Weg verstehen auch andere Entwickler den Programmtext, ohne lange nachzuforschen. In diesen Fällen sparen Kommentare sehr viel Zeit und Frust!
Als Programmierer sind Sie relativ frei darin, Leerzeichen, Tabulatoren oder auch leere Zeilen zu verwenden für Xcode macht es keinen Unterschied, wie Sie Ihren Programmtext formatieren. Informatiker haben für diese Art von Zeichen sogar einen eigenen Begriff, der sogenannte Leerraum (auf Englisch Whitespace). Für die Programmierung in Swift ist es nur wichtig, dass Sie pro Zeile nur eine Anweisung verwenden und Befehle und Variablen mit mindestens einem der drei genannten Leerraum-Zeichen voneinander trennen.
Sie dürfen ebenfalls mehr als eine einzige Anweisung in eine Zeile schreiben, indem Sie zwischen den Anweisungen ein Semikolon »;
« schreiben. In der Praxis empfiehlt es sich, davon nur sparsam Gebrauch zu machen. Ebenfalls empfiehlt es sich, nicht nur deswegen überall Leerzeilen einzufügen, weil man es kann. Beides ist sehr schlecht für die Lesbarkeit des Programmtextes.
Es gibt im Netz eine Reihe von sogenannten Coding Conventions, das heißt Richtlinien für die optische Gestaltung des Programmtextes, die die Lesbarkeit erhöhen sollen. Im Folgenden gebe ich Ihnen einige Empfehlungen, die ich auch im Rest des Buches anwende:
=
auf.allesObst
, kartenSuche
, zwischenSumme
.Hier sind einige Beispiele für schlechten und nur sehr schwer lesbaren Programmtext wobei ich einige Anweisungen benutze, die Sie erst in den nächsten Kapiteln kennenlernen werden, lassen Sie sich davon nicht abschrecken:
var b=0;for (var a=1;a<10;a+=1) {print("\(a)");b+=a}
var x=10;var y=0;while(x>0){x--=2;y+=1}
Diese Programmtexte könnten Sie folgendermaßen umschreiben, sodass ihre Bedeutung klarer wird:
// Gib die Zahlen 0 bis 9 aus und summiere sie.
var summe=0
for zahl in 1 ..< 10 {
print("\(zahl)")
summe += zahl
}
// Berechne, wie viele ungerade Zahlen es zwischen 0 und 10
// (einschließlich) gibt.
var zaehler = 10
var ergebnis = 0
while (zaehler > 0) {
zaehler --= 2
ergebnis += 1
}
Zum Schluss noch zwei allgemeine Ratschläge zur Organisation Ihres Programmtextes in einem Projekt:
Wenn Sie weitere Entwurfsmuster (wie beispielsweise MMVM/MVP) benutzen, so unterteilen Sie zusätzlich das Datenmodell in die Unterkategorien View model und reines Datenmodell.
In diesem fortgeschrittenen Teil spreche ich über die Unterschiede zwischen Zahlentypen. Warum brauchen Sie überhaupt verschiedene Datentypen und worin unterscheiden sich diese genau?
Warum mache ich mir überhaupt die Mühe, die Unterschiede von Double
und Int
zu erklären? Warum reicht es nicht einfach aus, immer mit Double
zu rechnen und, wenn es notwendig ist, auf Int
zu runden?
Der Grund ist, dass Ihr Computer intern nicht wirklich mit Fließkommazahlen rechnet, sondern in Wirklichkeit nur mit ganzen Zahlen und das auch noch mit lediglich begrenzter Genauigkeit. Fließkommazahlen haben daher in Wahrheit Beschränkungen, wie das folgende Beispiel zeigt. Bauen Sie mal die Anweisungen aus Listing 3.7 in Ihren Playground ein und lassen Sie es laufen.
var a:Float = 100000000.0 + 1.0
a = a -- 100000000.0
print("Ergebnis: \(a).")
Listing 3.7 Rechnung mit sehr großen Zahlen vom Typ »Float«
Das Ergebnis ist nicht etwa 1.0
, sondern
Ergebnis: 0.0.
Und mit Int
-Zahlen? Ersetzen Sie Float
durch Int
und passen Sie die Zahlen an, so wie es in Listing 3.8 gezeigt ist.
var i:Int = 100000000 + 1
i = i -- 100000000
print("Ergebnis: \(i).")
Listing 3.8 Rechnung mit sehr großen Zahlen vom Typ »Int«
Das Ergebnis ist hier tatsächlich korrekt:
Ergebnis: 1.
Aber auch beim Rechnen mit Int
-Werten kann einiges schiefgehen. Schauen Sie mal, was passiert, wenn Sie ein paar Nullen hinzufügen:
var iGross:Int = 1000000000000000000000
Hier kommt eine Fehlermeldung, die besagt, dass diese Zahl nicht mehr als Ganzzahl gespeichert werden kann. Andererseits könnten Sie diese allerdings als Fließkommazahl vom Typ Double
speichern:
var fGross:Double = 1000000000000000000000.0
Diese Zeile erzeugt keine Fehlermeldung, würde allerdings auch nicht exakt rechnen, wenn Sie kleine Zahlen zu fGross
hinzuaddieren. Weil Computer nicht wirklich unendliche Zahlen kennen, können sie einerseits nicht beliebig große Zahlen handhaben, andererseits aber auch nicht beliebig genau rechnen.
Es gibt in Swift noch eine Reihe weiterer Datentypen, die sich in ihrer Genauigkeit und in Ihrem Speicherplatzverbrauch unterscheiden. Außerdem gibt es Ganzzahlen, die nicht negativ werden können. Diese sind:
Int8
, Int16
, Int32
und Int64
: Diese Typen sind Ganzzahlen, die zwischen 2n1 und 2n11 liegen, wobei n die Zahl hinter Int
ist.
UInt8
, UInt16
, UInt32
und UInt64
: Diese Typen sind Ganzzahlen, die zwischen 0 und 2n1 liegen, wobei n die Zahl hinter UInt
ist.
Ein Int8
kann also beispielsweise Zahlen zwischen -128 und 127 speichern. Was passiert aber nun, wenn wir zu 127 eine 1 hinzuaddieren? In Sprachen wie Objective-C wäre das Ergebnis 128! Swift erzeugt hier einen Fehler, was deutlich auf das Problem hinweist. Diese Art von Problemen nennen sich Überlauf-Fehler (englisch Overflow). Ein Overflow ist ein Problem, das selbst den besten Programmierern zu schaffen machen kann. So war beispielsweise der Absturz der ersten Ariane-5-Rakete einem solchen Overflow geschuldet hier finden Sie eine ausführliche Beschreibung: http://de.wikipedia.org/wiki/Ariane_V88.
Sollten Sie einmal Zahlen verwenden, die sich nicht auf diese Art und Weise darstellen lassen, so müssen Sie Zusatzsoftware verwenden, zum Beispiel die Gnu Multiple Precision Arithmetic Library, siehe http://gmplib.org. Aber machen Sie sich keine großen Sorgen deswegen: In den allermeisten Fällen lösen Sie alle Probleme mit Int
und Double
, ohne in die Verlegenheit zu kommen, die ganzen Details der fortgeschrittenen Datentypen zu verstehen!
Dies sind hauptsächlich Aufgaben zu Bool
-Werten. Diese sind in der Praxis sehr wichtig, weil sie es erlauben, Bedingungen und Annahmen präzise zu formulieren. Ein guter Programmierer sollte sich daher ständig in Bool
-Ausdrücken üben.
(a || !a)
?
((a == 1) && (a==2))
?
!(((a > 0) || (a < 0)) && (a == 0))
?
(false || (true && (true || false)))
((a > 3) && (a < 4))
?
(a != 2)
?
(a + b < 100)
gleich true
?