Seit Apple SwiftUI auf der WWDC 2019 vorgestellt hat, hat sich die iOS-Entwicklung grundlegend gewandelt. Was früher Dutzende Zeilen UIKit-Code erforderte, lässt sich heute in wenigen Zeilen deklarativem Swift-Code ausdrücken. In diesem Artikel bekommst du einen umfassenden Einstieg in SwiftUI: von den Kernkonzepten über praktische Code-Beispiele bis hin zu den häufigsten Fragen von Einsteigern.
Was ist SwiftUI?
SwiftUI ist Apples modernes UI-Framework für alle Plattformen des Unternehmens – also iOS, macOS, watchOS, tvOS und visionOS. Es wurde entwickelt, um das ältere UIKit langfristig abzulösen, und basiert auf einem vollständig neuen Ansatz: der deklarativen Programmierung.
Statt dem System Schritt für Schritt zu sagen, wie die Oberfläche aufgebaut werden soll (imperativ), beschreibst du mit SwiftUI, was die Oberfläche zeigen soll – und das Framework kümmert sich selbst um die Aktualisierung, wenn sich Daten ändern. Das reduziert Fehler und macht den Code erheblich lesbarer.
Deklarativ vs. imperativ – der Kernunterschied
In UIKit (imperativ) erstellst du ein Label, setzt dessen Text, fügst es als Subview hinzu, konfigurierst Auto Layout-Constraints und aktualisierst alles manuell, wenn sich Daten ändern:
// UIKit – imperativ
let label = UILabel()
label.text = "Hallo Welt"
label.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(label)
NSLayoutConstraint.activate([
label.centerXAnchor.constraint(equalTo: view.centerXAnchor),
label.centerYAnchor.constraint(equalTo: view.centerYAnchor)
])
In SwiftUI (deklarativ) beschreibst du das Ergebnis direkt:
// SwiftUI – deklarativ
Text("Hallo Welt")
.frame(maxWidth: .infinity, maxHeight: .infinity)
Der SwiftUI-Code ist kürzer, klarer und reagiert automatisch auf Zustandsänderungen – ohne dass du manuell reloadData() oder ähnliches aufrufen musst.
Views und Modifiers – die Bausteine von SwiftUI
Alles in SwiftUI ist eine View. Ein Text, ein Button, ein Bild, ein Stack – sogar dein gesamter Bildschirm ist eine View. Views sind in SwiftUI einfache Structs, die dem Protokoll View entsprechen und eine berechnete Eigenschaft body implementieren.
struct MeineBegrüßung: View {
var name: String
var body: some View {
Text("Hallo, \(name)!")
.font(.title)
.foregroundStyle(.blue)
.padding()
}
}
Die Methoden, die du auf eine View anwendest – wie .font(), .foregroundStyle() oder .padding() – nennt man Modifiers. Jeder Modifier gibt eine neue, modifizierte View zurück. Diese Kette von Modifiers ist das Herzstück des SwiftUI-Designs und macht den Code linear lesbar.
Layout-Container: HStack, VStack, ZStack
Für die Anordnung von Views gibt es drei grundlegende Container:
VStack– stapelt Views vertikalHStack– stapelt Views horizontalZStack– legt Views übereinander (z-Achse)
VStack(spacing: 16) {
Text("Titel")
.font(.headline)
HStack {
Image(systemName: "star.fill")
.foregroundStyle(.yellow)
Text("5 Sterne")
}
}
Dazu kommen List, ScrollView, Grid, LazyVStack und viele weitere Container für spezifische Anwendungsfälle.
State und Binding – Reaktive Datenverwaltung
Das mächtigste Konzept in SwiftUI ist die reaktive Datenbindung. Statt Daten manuell in die UI zu schreiben, verknüpfst du Views direkt mit Datenquellen. SwiftUI aktualisiert die UI automatisch, wenn sich die Daten ändern.
@State – lokaler Zustand einer View
@State ist die einfachste Form der Datenbindung. Du verwendest sie für Werte, die nur innerhalb einer View relevant sind – zum Beispiel ob ein Toggle aktiviert ist oder welcher Text gerade im Textfeld steht:
struct ZählerView: View {
@State private var zähler = 0
var body: some View {
VStack(spacing: 20) {
Text("Zähler: \(zähler)")
.font(.largeTitle)
Button("Erhöhen") {
zähler += 1
}
.buttonStyle(.borderedProminent)
}
}
}
Jedes Mal, wenn du auf den Button tippst, erhöht sich zähler – und SwiftUI rendert die View automatisch neu.
@Binding – Zustand zwischen Views teilen
@Binding ermöglicht es, den Zustand einer übergeordneten View an eine untergeordnete View weiterzugeben, sodass beide auf denselben Wert zugreifen und ihn verändern können:
struct EingabeView: View {
@Binding var text: String
var body: some View {
TextField("Name eingeben", text: $text)
.textFieldStyle(.roundedBorder)
}
}
struct ElternView: View {
@State private var name = ""
var body: some View {
VStack {
EingabeView(text: $name)
Text("Hallo, \(name)!")
}
}
}
@Observable und @Environment für komplexere Apps
Für größere Apps empfiehlt sich das @Observable-Makro (ab iOS 17) oder ObservableObject mit @StateObject / @ObservedObject für ältere iOS-Versionen. Damit lagerst du Geschäftslogik in separate Klassen aus und hältst deine Views schlank.
NavigationStack – Navigationshierarchien aufbauen
Ab iOS 16 ist NavigationStack die empfohlene Methode für hierarchische Navigation. Es ersetzt das ältere NavigationView und bietet deutlich mehr Kontrolle über den Navigationspfad:
NavigationStack {
List(artikel) { artikel in
NavigationLink(artikel.titel, value: artikel)
}
.navigationTitle("Artikel")
.navigationDestination(for: Artikel.self) { artikel in
ArtikelDetailView(artikel: artikel)
}
}
Mit navigationDestination(for:) kannst du typsicher definieren, welche View für welchen Datentyp angezeigt wird. Der NavigationPath ermöglicht außerdem programmatische Navigation – du kannst Screens per Code aufrufen oder den Navigationsstapel zurücksetzen.
@ViewBuilder – Views kompositorisch zusammensetzen
@ViewBuilder ist ein Result Builder, der es erlaubt, mehrere Views in einem Funktionskörper oder einer Closure zu deklarieren, ohne explizit einen Container zurückzugeben. Du nutzt ihn immer dann, wenn du eigene Container-Views oder wiederverwendbare Layout-Komponenten baust:
struct KartenView<Inhalt: View>: View {
@ViewBuilder let inhalt: () -> Inhalt
var body: some View {
inhalt()
.padding()
.background(.white)
.cornerRadius(12)
.shadow(radius: 4)
}
}
Die Preview Canvas – Live-Vorschau in Xcode
Einer der größten Vorteile von SwiftUI ist die Preview Canvas in Xcode. Mit dem #Preview-Makro (ab Xcode 15) kannst du deine Views live im Editor sehen, ohne die App jedes Mal neu kompilieren und im Simulator starten zu müssen:
#Preview {
ZählerView()
}
Du kannst mehrere Previews für verschiedene Gerätegrößen, Schriftgrößen oder Dark/Light Mode definieren und so sicherstellen, dass deine UI in allen Szenarien korrekt aussieht.
SwiftUI vs. UIKit – was solltest du 2026 lernen?
Für neue Projekte ist SwiftUI heute die klare Empfehlung. Apple investiert seit Jahren intensiv in SwiftUI und hat Lücken, die früher UIKit-Kenntnisse erzwangen, größtenteils geschlossen. Für folgende Punkte lohnt sich SwiftUI besonders:
- Schnellere Entwicklung durch weniger Boilerplate-Code
- Cross-Platform-Support (iOS, macOS, watchOS, tvOS, visionOS) mit gemeinsamer Codebasis
- Automatische Anpassung an Systemfeatures (Dynamic Type, Dark Mode, Accessibility)
- Bessere Testbarkeit durch klare Datentrennung
UIKit bleibt dennoch relevant: Bestehende große Projekte, spezifische UI-Komponenten ohne SwiftUI-Äquivalent und maximale Performance-Kontrolle sind Szenarien, in denen du UIKit nach wie vor brauchst. Beide Frameworks lassen sich übrigens kombinieren – mit UIViewRepresentable kannst du UIKit-Views in SwiftUI einbetten.
Schau dir auch die iOS Apps von Arthur Kotsch an – alle aktuellen Apps sind vollständig mit SwiftUI gebaut.
Praktisches Beispiel: Eine einfache Aufgaben-App
Zum Abschluss ein vollständiges, minimales Beispiel einer Aufgaben-App, die die wichtigsten SwiftUI-Konzepte kombiniert:
struct Aufgabe: Identifiable {
let id = UUID()
var titel: String
var erledigt: Bool = false
}
struct AufgabenApp: View {
@State private var aufgaben = [
Aufgabe(titel: "SwiftUI lernen"),
Aufgabe(titel: "Erste App veröffentlichen"),
Aufgabe(titel: "App Store Connect einrichten")
]
@State private var neueAufgabe = ""
var body: some View {
NavigationStack {
List {
ForEach($aufgaben) { $aufgabe in
HStack {
Image(systemName: aufgabe.erledigt
? "checkmark.circle.fill" : "circle")
.foregroundStyle(aufgabe.erledigt ? .green : .gray)
.onTapGesture { aufgabe.erledigt.toggle() }
Text(aufgabe.titel)
.strikethrough(aufgabe.erledigt)
}
}
}
.navigationTitle("Aufgaben")
.toolbar {
ToolbarItem(placement: .bottomBar) {
HStack {
TextField("Neue Aufgabe", text: $neueAufgabe)
Button("Hinzufügen") {
guard !neueAufgabe.isEmpty else { return }
aufgaben.append(Aufgabe(titel: neueAufgabe))
neueAufgabe = ""
}
}
}
}
}
}
}
Dieser Code ist vollständig funktionsfähig und zeigt, wie wenig Code für eine interaktive, datengetriebene App nötig ist. Wenn du bereit bist, deine App zu veröffentlichen, lies den Artikel zur App Store Veröffentlichung.
Häufige Fragen
Muss ich Swift kennen, bevor ich SwiftUI lerne?
Ja, grundlegende Swift-Kenntnisse sind Voraussetzung. Du solltest Konzepte wie Structs, Closures, Optionals und Protokolle verstehen, bevor du mit SwiftUI startest. Apple bietet dafür exzellente kostenlose Ressourcen über die Swift Playgrounds App.
Ab welcher iOS-Version wird SwiftUI unterstützt?
SwiftUI erfordert mindestens iOS 13. Viele moderne Features wie NavigationStack oder @Observable sind jedoch erst ab iOS 16 bzw. iOS 17 verfügbar. Für neue Apps empfiehlt sich ein Mindest-Deployment-Target von iOS 17, da der Marktanteil älterer Versionen kontinuierlich sinkt.
Kann ich SwiftUI und UIKit in einem Projekt mischen?
Ja. Mit UIViewRepresentable und UIViewControllerRepresentable bindest du UIKit-Komponenten in SwiftUI ein. Umgekehrt kannst du SwiftUI-Views mit UIHostingController in UIKit-Apps einbetten. Das erleichtert die schrittweise Migration bestehender Projekte.
Wie teste ich SwiftUI-Apps?
SwiftUI unterstützt Unit Tests für deine ViewModels und Logik-Schichten sowie Snapshot-Tests für die UI. Mit dem TestFlight-Dienst kannst du Beta-Versionen an Tester verteilen, bevor du die App öffentlich veröffentlichst. Mehr dazu in der TestFlight-Anleitung.
Ist SwiftUI für komplexe Apps geeignet?
Ja. Große Apps wie Apples eigene Fitness-App oder viele Top-100-Apps im App Store nutzen SwiftUI vollständig oder als dominante UI-Schicht. Mit sauber getrennter Architektur (MVVM, TCA oder ähnlich) skaliert SwiftUI problemlos für umfangreiche Projekte.