Lernziel
Nach dieser Lektion kannst du Code mit for-in eine bestimmte Anzahl von Malen wiederholen, mit while so lange wiederholen, bis eine Bedingung erfüllt ist, und Schleifen mit break und continue steuern.
Das Problem: Copy & Paste
Stell dir vor, du willst einen Countdown von 5 bis 1 ausgeben. Mit dem, was du bisher weißt:
print(5)
print(4)
print(3)
print(2)
print(1)
print("Start!")Für fünf Zahlen geht das noch. Aber für 100? Oder für eine Anzahl, die du vorher gar nicht kennst, etwa so viele Zeilen, wie ein Nutzer Einträge hat?
Programmierer haben eine eiserne Regel: Wiederhole dich nicht (englisch Don't Repeat Yourself, kurz DRY). Wenn du Code kopierst und nur eine Kleinigkeit änderst, gibt es fast immer einen besseren Weg. Für Wiederholungen ist das die Schleife.
for-in: Zählen
Die häufigste Schleife in Swift:
for number in 1...5 {
print(number)
}Ausgabe:
1
2
3
4
5So liest du das: „Für jede Zahl in dem Bereich von 1 bis 5: Führe den Block aus.“
Bei jedem Durchlauf bekommt number den nächsten Wert aus dem Bereich. Den Namen number darfst du frei wählen. Er gilt nur innerhalb der geschweiften Klammern.
Bereiche kennst du aus Lektion 1.4:
for i in 0..<3 {
print("Durchlauf \(i)")
}
// Durchlauf 0
// Durchlauf 1
// Durchlauf 2Tipp
0..<3 läuft dreimal: 0, 1, 2. Diese Form siehst du in der Programmierung sehr oft, weil Computer meist bei 0 zu zählen beginnen. Mehr dazu in Lektion 1.6.
Wenn du die Zahl gar nicht brauchst
Manchmal willst du etwas nur x-mal wiederholen und brauchst den Zähler nicht. Dann schreibst du statt eines Namens einen Unterstrich:
for _ in 1...3 {
print("Hip hip hurra!")
}Der _ bedeutet in Swift: „Hier steht etwas, das mich nicht interessiert.“ Er wird dir noch öfter begegnen.
Rückwärts zählen und in Schritten
Für unseren Countdown brauchen wir die Zahlen rückwärts:
for number in (1...5).reversed() {
print(number)
}
print("Start!")Und für Schritte, etwa nur jede zweite Zahl, gibt es stride:
for number in stride(from: 0, to: 10, by: 2) {
print(number) // 0, 2, 4, 6, 8
}stride(from:to:by:) zählt ohne den Endwert, stride(from:through:by:) mit.
Mit Werten rechnen
Schleifen sind besonders mächtig in Kombination mit Variablen. Hier wird die Summe der Zahlen von 1 bis 100 berechnet:
var sum = 0
for number in 1...100 {
sum += number
}
print(sum) // 5050Die Variable sum steht vor der Schleife. Stünde sie innerhalb, würde sie bei jedem Durchlauf neu bei 0 beginnen.
Über Texte laufen
for-in funktioniert nicht nur mit Zahlen, sondern mit allem, was aus mehreren Teilen besteht, zum Beispiel mit den Buchstaben eines Strings:
for letter in "Swift" {
print(letter)
}
// S, w, i, f, t (je in einer Zeile)In der nächsten Lektion lernst du Arrays kennen, Listen von Werten. Mit for-in gehst du sie Element für Element durch. Das ist mit Abstand der häufigste Einsatz von Schleifen.
while: Solange …
Manchmal weißt du vorher nicht, wie oft etwas wiederholt werden muss. Du weißt nur, wann es aufhören soll. Dafür gibt es while:
var balance = 100
var months = 0
while balance > 0 {
balance -= 30
months += 1
}
print("Das Geld reicht \(months) Monate.") // 4So funktioniert es: Vor jedem Durchlauf prüft Swift die Bedingung. Ist sie true, läuft der Block. Ist sie false, geht es nach der Schleife weiter.
Endlosschleifen
Wird die Bedingung nie false, läuft die Schleife für immer:
var count = 0
while count < 5 {
print(count)
// count += 1 vergessen!
}Dein Playground hängt sich dann auf. Klick auf den Stop-Button. Prüfe bei jeder while-Schleife: Ändert sich im Block etwas, das die Bedingung irgendwann false macht?
repeat-while: Mindestens einmal
repeat-while prüft die Bedingung erst nach dem Durchlauf. Der Block läuft also mindestens einmal:
var dice = 0
repeat {
dice = Int.random(in: 1...6)
print("Gewürfelt: \(dice)")
} while dice != 6Würfeln, bis eine 6 kommt. Ohne den ersten Wurf gäbe es ja nichts zu prüfen. Int.random(in:) liefert übrigens eine Zufallszahl im angegebenen Bereich.
for oder while?
for-in, wenn du weißt, wie oft oder worüber du laufen willst. In der Praxis ist das der Normalfall.while, wenn du nur weißt, bis wann.
Schleifen steuern: break und continue
continue: Diesen Durchlauf überspringen
for number in 1...10 {
if number % 2 == 0 {
continue
}
print(number)
}
// 1, 3, 5, 7, 9Bei geraden Zahlen springt continue sofort zum nächsten Durchlauf. Das print wird übersprungen.
break: Schleife ganz beenden
let numbers = 1...100
for number in numbers {
if number * number > 50 {
print("Erste Zahl, deren Quadrat größer als 50 ist: \(number)")
break
}
}
// Erste Zahl, deren Quadrat größer als 50 ist: 8Sobald das Gesuchte gefunden ist, beendet break die Schleife. Die restlichen Zahlen werden gar nicht mehr angeschaut.
Verschachtelte Schleifen
Schleifen können in Schleifen stehen. Ein klassisches Beispiel ist das kleine Einmaleins:
for row in 1...3 {
for column in 1...3 {
print("\(row) × \(column) = \(row * column)")
}
}Für jeden Durchlauf der äußeren Schleife läuft die innere Schleife komplett durch. Bei 3 × 3 sind das also 9 Ausgaben.
Typische Fehler
Bereich falsch herum
for i in 5...1 {
print(i)
}Fehlermeldung
Laufzeitfehler: Range requires lowerBound <= upperBound
Der Code stürzt ab. Ein Bereich muss immer vom kleineren zum größeren Wert gehen. Für rückwärts: (1...5).reversed().
Variable in der Schleife statt davor
for number in 1...3 {
var sum = 0
sum += number
}
print(sum)Fehlermeldung
Cannot find 'sum' in scope
sum existiert nur innerhalb der Schleife und beginnt bei jedem Durchlauf wieder bei 0. Leg die Variable vor der Schleife an.
Schleifenvariable ändern
for i in 1...5 {
i += 1
}Fehlermeldung
Left side of mutating operator isn't mutable: 'i' is a 'let' constant
Die Schleifenvariable ist eine Konstante. Swift setzt sie selbst bei jedem Durchlauf. Du darfst sie lesen, aber nicht ändern.
Endlosschleife
Der Playground reagiert nicht mehr, der Ladebalken dreht sich. Stop-Button drücken und prüfen, ob sich die while-Bedingung im Block wirklich ändert.
FAQ
Anfänger
Was bedeutet das überhaupt?Warum heißt die Zählvariable so oft i?
Das ist eine alte Tradition aus der Mathematik (index). Für einfache Zähler ist i in Ordnung. Wenn die Variable etwas Bestimmtes darstellt, nimm einen sprechenden Namen wie month oder player.
Wie oft darf eine Schleife laufen? Theoretisch unbegrenzt. Praktisch merkst du ab vielen Millionen Durchläufen, dass es dauert, besonders im Playground, der jede Zeile protokolliert.
Fortgeschritten
Warum verhält es sich so?Was mache ich bei verschachtelten Schleifen, wenn ich beide beenden will?
break beendet nur die innere Schleife. Mit einem Label kannst du gezielt die äußere beenden:
outer: for row in 1...5 {
for column in 1...5 {
if row * column == 6 {
break outer
}
}
}Brauchst du das oft, ist der Code meist zu verschachtelt. Dann hilft eine eigene Funktion (Lektion 1.10).
Gibt es Alternativen zu Schleifen?
Ja. Für viele typische Aufgaben, etwa „alle Werte verdoppeln“ oder „nur bestimmte Werte behalten“, gibt es fertige Funktionen wie map und filter. Du lernst sie in Lektion 1.11 kennen. In SwiftUI selbst schreibst du übrigens fast nie for-Schleifen. Dort gibt es ForEach (Lektion 2.15).
Profi
Was passiert unter der Haube?Wie funktioniert for-in unter der Haube?
for-in funktioniert mit allem, was das Protokoll Sequence erfüllt. Swift holt sich davon einen Iterator und ruft so lange next() auf, bis nil zurückkommt. Bereiche, Strings, Arrays und Dictionaries erfüllen alle Sequence. Was Protokolle sind und was nil bedeutet, lernst du in den Lektionen 1.15 und 1.8.
Warum stürzt 5...1 ab, statt einfach nichts zu tun?
Weil ein Bereich mit vertauschten Grenzen fast immer ein Logikfehler ist. Swift folgt dem Prinzip, solche Fehler früh und laut zu melden, statt stillschweigend weiterzumachen.
Übungen
Übung 1: Einmaleins
Gib die 7er-Reihe von 7 × 1 bis 7 × 10 aus, jeweils in der Form „7 × 3 = 21“.
Lösung Übung 1Erst selbst probieren!
for i in 1...10 {
print("7 × \(i) = \(7 * i)")
}Übung 2: FizzBuzz
Der Klassiker unter den Programmieraufgaben: Gib die Zahlen von 1 bis 30 aus. Ist eine Zahl durch 3 teilbar, gib stattdessen „Fizz“ aus, ist sie durch 5 teilbar, „Buzz“, und ist sie durch beides teilbar, „FizzBuzz“.
Lösung Übung 2Erst selbst probieren!
for number in 1...30 {
if number % 15 == 0 {
print("FizzBuzz")
} else if number % 3 == 0 {
print("Fizz")
} else if number % 5 == 0 {
print("Buzz")
} else {
print(number)
}
}Der Fall „durch beides teilbar“ muss zuerst geprüft werden. Sonst würde bei 15 schon die Bedingung für 3 greifen. Erinnerst du dich an Lektion 1.4? Vom speziellsten zum allgemeinsten Fall.
Übung 3: Sparplan
Du legst 1.000 € zu 3 % Zinsen pro Jahr an. Die Zinsen werden jedes Jahr mitverzinst. Nach wie vielen Jahren hast du zum ersten Mal mehr als 2.000 €? Löse das mit einer while-Schleife.
Lösung Übung 3Erst selbst probieren!
var money = 1000.0
var years = 0
while money <= 2000 {
money *= 1.03
years += 1
}
print("Nach \(years) Jahren: \(money) €")
// Nach 24 Jahren: 2032.79… €Zusammenfassung
for-inläuft über einen Bereich oder eine Sammlung von Werten._statt eines Namens, wenn du den Wert nicht brauchst.whilewiederholt, solange eine Bedingungtrueist. Vorsicht vor Endlosschleifen.repeat-whileläuft mindestens einmal.continueüberspringt einen Durchlauf,breakbeendet die Schleife.- Variablen, die über alle Durchläufe gelten sollen, gehören vor die Schleife.
Spickzettel
for i in 1...5 { ... } // 1 bis 5
for i in 0..<5 { ... } // 0 bis 4
for _ in 1...3 { ... } // 3-mal, ohne Zähler
for i in (1...5).reversed() { ... } // rückwärts
for i in stride(from: 0, to: 10, by: 2) { ... }
while condition { ... }
repeat { ... } while condition
continue // nächster Durchlauf
break // Schleife beenden