10. Oktober 2019

SwiftUI Tutorial: Einführung und Verwendung von @State

Das folgende Tutorial vermittelt anhand einer Würfel-App die Grundlagen zur Oberflächenentwicklung mit SwiftUI und die Verwendung von @State.

Verwende für dieses Tutorial Xcode 11. Die Live-Vorschau funktioniert nur unter macOS Catalina, alle weiteren Funktionalitäten können auch unter Mojave verwendet werden (siehe Verwendung von SwiftUI unter Mojave).

  1. Erstelle mit File » New » Project... ⌘⇧N ein neues Xcode-Projekt Dice. Verwende die Vorlage Single View App und wähle als User Interface-Framework SwiftUI aus:

    Neues Xcode-Projekt anlegen
  2. Öffne die Datei ContentView.swift im Projekt und mache Dich mit dem erstellten Code vertraut.

    Es wurde ein struct-Typ ContentView erstellt, der konform zum View-Protokoll deklariert ist - in SwiftUI werden alle Views als Wertetyp konform zu dem View-Protokoll deklariert. Dieses Protokoll fordert die Eigenschaft body, die das View für die Anzeige „berechnet“:

    struct ContentView: View {
    
        var body: some View {
            Text("Hello World")
        }
    
    }

    Zusätzlich wird ein PreviewProvider für das View deklariert - dieser konfiguriert die Vorschau in Xcode:

    struct ContentView_Previews: PreviewProvider {
    
        static var previews: some View {
            ContentView()
        }
    
    }
  3. Blende die Canvas-Vorschau ein:

    Canvas-Vorschau für SwiftUI

    Aktiviere die Vorschau mit Resume (dies kann beim ersten Mal etwas dauern, da Xcode für die Live-Vorschau das Projekt bauen muss):

    Resume Canvas-Vorschau
  4. Ändere den Text zu Hallo SwiftUI - die Vorschau wird unmittelbar aktualisiert:

    Unmittelbare Aktualisierung der SwiftUI-Vorschau
  5. Probiere die verschiedenen Möglichkeiten aus, Views über Modifier zu verändern.

    via -Klick im Code » Show SwiftUI Inspector…:

    SwiftUI-Inspektor via Code

    oder über -Klick in der Canvas-Vorschau:

    SwiftUI-Inspektor via Vorschau

    oder über den Attributes Inspector:

    SwiftUI-Attribute über Attributes-Inspektor berarbeiten
  6. Füge über die Library einen Button unterhalb des Labels hinzu:

    Button hinzufügen

    Der Editor wird automatisch ein gruppierendes VStack-Element erzeugen, welches Text-Label und Button übereinander stapelt:

    VStack {
        Text("Hallo SwiftUI")
        Button(action: {}) {
            Text("Button")
        }
    }
  7. Ändere den Button-Text zu „Würfeln“, vergib einen spacing-Abstand für den VStack und setze die Schrift für das Label als Large Title, so dass sich folgendes View ergibt:

    View mit veränderten Eigenschaften
  8. Deklariere eine Eigenschaft number, die die Würfelzahl enthält und erzeuge sofort eine Würfelzahl. Verwende diese für die Anzeige als Text:

    struct ContentView: View {
        
        var number = Int.random(in: 1...6)
        
        var body: some View {
            VStack(spacing: 20.0) {
                Text( String(number))
                    .font(.largeTitle)
                Button(action: {}) {
                    Text("Würfeln")
                }
            }
        }
    }
  9. Implementiere den action-Block des Buttons so, dass eine neue Würfelzahl generiert wird. Dies wird einen Compilerfehler auslösen: „Cannot assign to property: 'self' is immutable“:

    Cannot assign to property: 'self' is immutable

    Wertetypen in Swift sind standardmäßig unveränderbar (immutable) und können nur innerhalb von als mutating deklarierten Methoden verändert werden. Für SwiftUI wurde daher ein sog. Property Wrapper @State bereitgestellt, der veränderbaren Zustand (wie die Würfelzahl) innerhalb von SwiftUI-Views erlaubt.

    Jede Änderung einer @State-Eigenschaft bewirkt automatisch eine Aktualisierung des Views, indem die body-Eigenschaft erneut berechnet wird.

  10. Verwende @State für die number-Eigenschaft:

    struct ContentView: View {
        
        @State var number = Int.random(in: 1...6)
        
        var body: some View {
            VStack(spacing: 20.0) {
                Text(String(number))
                    .font(.largeTitle)
                Button(action: {
                    self.number = Int.random(in: 1...6)
                }) {
                    Text("Würfeln")
                }
            }
        }
    }
  11. Verwende die Live-Preview um eine interaktive Vorschau des Views zu testen (oder starte die App regulär via ⌘R):

  12. Vereinfache den Code um den Button zu erzeugen - es gibt eine Variante von dem Button-Initializer, bei dem der action-Block als Trailing Closure übergeben wird:

    Button("Würfeln") {
        self.number = Int.random(in: 1...6)
    }
  13. Füge dem Text-View noch einige Modifier hinzu, um folgende Darstellung zu realisieren:

    Zum Beispiel:

    Text(String(self.number))
        .frame(width: 80, height: 80)
        .font(.largeTitle)
        .foregroundColor(Color.red)
        .border(Color.red, width: 3)
        .background(Color.yellow)
        .shadow(radius: 10)