SwiftUI — Apple's declaratieve framework voor het bouwen van gebruikersinterfaces op alle platformen van het ecosysteem, geïntroduceerd op WWDC 2019. In tegenstelling tot het imperatieve UIKit met zijn viewDidLoad en handmatige schermvernieuwing, beschrijft SwiftUI UI als een verzameling eenvoudige structuren die voldoen aan het View-protocol. Volgens Swift.org (2025) wordt SwiftUI gebruikt in 65% van de nieuwe projecten die in de App Store zijn gepubliceerd. Het framework beheert automatisch de interface-updates via het State en Data Flow-mechanisme — wanneer gegevens veranderen, wordt View opnieuw getekend zonder handmatige aanroep van reloadData.
Belangrijkste punten
SwiftUI — Apple's declaratieve UI-framework, radicaal anders dan UIKit. In plaats van controllers, views en het handmatig beheren van hun levenscyclus, beschrijft de ontwikkelaar de interface in de vorm van declaraties: wat er op het scherm moet verschijnen, niet hoe het gebouwd moet worden. SwiftUI is gebaseerd op het principe van reactiviteit: de interface is een functie van de toestand. Bij verandering van toestand (State) herberekent SwiftUI automatisch de body van alle afhankelijke Views en werkt alleen de gewijzigde delen van het scherm bij. SwiftUI is beschikbaar op iOS 13+, iPadOS 13+, macOS 10.15+, watchOS 6+, tvOS 13+ en visionOS 1+. SwiftUI-code is cross-platform: één bestand werkt op iPhone, iPad, Mac en Apple Watch met minimale platformaanpassingen. Volgens Apple WWDC Session 101 (2024) dekt SwiftUI meer dan 90% van de standaard UI-patronen van de App Store.
UIKit — het imperatieve framework (2008): de ontwikkelaar maakt een UIViewController, configureert subviews in viewDidLoad, implementeert delegate/datasource voor UITableView en werkt het scherm bij via reloadData of setNeedsLayout. SwiftUI vervangt controllers door eenvoudige View-structuren, delegaten door binding en onChange, Auto Layout door HStack/VStack/ZStack met modificatoren (padding, frame, offset). UIKit vereist handmatig geheugenbeheer via ARC; SwiftUI — structuren die geen referentietelling nodig hebben. De prestaties van SwiftUI zijn vergelijkbaar met UIKit: het framework gebruikt een diffing-algoritme voor een minimale set wijzigingen. Bij IT Sectr wordt SwiftUI gebruikt voor nieuwe projecten met iOS 17+ target; projecten met ondersteuning voor iOS 14–15 vereisen UIKit vanwege de beperkte compatibiliteit van SwiftUI.
In SwiftUI wordt de interface beschreven via ViewBuilder — een result builder die een set Views transformeert naar een tuple of Group. Modificatoren (.padding(), .font(), .foregroundColor()) creëren nieuwe Views met gewijzigde instellingen, muteren niet het originele object. Elke modificator retourneert een nieuwe View, wat chaining mogelijk maakt. ViewBuilder ondersteunt if/else, switch, ForEach — conditionele en cyclische weergave zonder aparte controllers. View in SwiftUI is een value type (struct), wat voorspelbaar gedrag garandeert en race conditions elimineert.
View — een protocol met één vereiste: computed property body van het type some View. Elke structuur die voldoet aan View beschrijft zijn deel van het scherm in body. Het type some View — opaque return type dat het concrete type van de geretourneerde View verbergt (samenstelling van VStack, HStack, ZStack, Text, Image enz.). De Swift-compiler leidt het concrete type af tijdens de compilatiefase, waardoor de prestaties van directe aanroep behouden blijven zonder type-uitwissing.
import SwiftUI
struct GreetingView: View {
var name: String
var body: some View {
VStack(spacing: 12) {
Text("Hallo, \(name)!")
.font(.largeTitle)
.foregroundColor(.primary)
Text("Welkom bij SwiftUI")
.font(.body)
.foregroundColor(.secondary)
}
.padding()
.background(
RoundedRectangle(cornerRadius: 12)
.fill(.ultraThinMaterial)
)
}
}De structuur GreetingView accepteert de parameter name en toont twee tekstblokken in een verticale stack. De modificatoren .font, .foregroundColor, .padding en .background configureren het uiterlijk. SwiftUI roept body aan telkens wanneer de invoerparameters (name) veranderen — het opnieuw tekenen vindt alleen plaats voor de gewijzigde delen. In het voorbeeld wordt RoundedRectangle met .ultraThinMaterial gebruikt — native blur-achtergrond ingebouwd in SwiftUI.
@State — een property wrapper die lokale toestand declareert die aan één View toebehoort. SwiftUI beheert het geheugen van State automatisch: bij verandering van de waarde wordt body opnieuw getekend, maar alleen voor Views die deze State gebruiken. State is de bron van waarheid (source of truth) voor eenvoudige typen (String, Int, Bool, enum). Gebruik @State niet voor complexe gegevensmodellen — daarvoor zijn @StateObject en @ObservedObject bedoeld. State moet private zijn en in de View zelf worden opgeslagen, niet worden doorgegeven tussen componenten.
import SwiftUI
struct CounterView: View {
@State private var count = 0
var body: some View {
VStack(spacing: 20) {
Text("Aantal: \(count)")
.font(.system(size: 48, weight: .bold))
Button(action: { count += 1 }) {
Label("Verhoog", systemImage: "plus.circle")
}
.buttonStyle(.borderedProminent)
}
.padding()
}
}Beginwaarde count = 0. Elke druk op de knop verhoogt count; SwiftUI tekent CounterView automatisch volledig opnieuw (alle Views). In UIKit zou een vergelijkbaar scenario IBOutlet, IBAction en handmatige bijwerking van label.text hebben vereist. @State garandeert dat View alleen opnieuw wordt getekend bij verandering van een specifieke State — het diffing-algoritme van SwiftUI vindt minimale wijzigingen in de boomstructuur.
@Binding — een property wrapper die een tweerichtingsverbinding creëert tussen een View en gegevens die de View niet beheert. Binding is een verwijzing naar State (of een andere bron van waarheid), waarmee een kind-View de waarde die in de ouder is opgeslagen kan lezen en wijzigen. Binding wordt aangeduid met het $-prefix: $count geeft Binding<Int> door aan de kind-View. Zonder Binding kan de kind-View de gegevens van de ouder niet wijzigen — alleen lezen.
import SwiftUI
struct StepperControl: View {
@Binding var value: Int
let range: ClosedRange<Int>
var body: some View {
HStack {
Button(action: { if value > range.lowerBound { value -= 1 } }) {
Image(systemName: "minus.circle")
}
Text("\(value)")
.frame(minWidth: 40)
Button(action: { if value < range.upperBound { value += 1 } }) {
Image(systemName: "plus.circle")
}
}
}
}
struct ParentView: View {
@State private var quantity = 5
var body: some View {
StepperControl(value: $quantity, range: 1...10)
}
}ParentView bezit de State quantity en geeft Binding door via $quantity. StepperControl kan value wijzigen, en quantity in de ouder wordt automatisch gesynchroniseerd. Binding is geen kopie van gegevens, maar een brug naar de bron van waarheid. Gebruik @Binding voor aangepaste besturingselementen, editors en herbruikbare componenten die gegevens van de ouder moeten wijzigen.
@StateObject — een property wrapper voor het maken en bezitten van een instantie van een klasse die voldoet aan ObservableObject. De View maakt het object eenmaal per levenscyclus en wordt opnieuw getekend bij verandering van de @Published-eigenschappen. @ObservedObject — een vergelijkbare wrapper, maar de View bezit het object niet — het object wordt buiten de View gemaakt en opgeslagen (doorgegeven via de initialisator). Apple beveelt @StateObject aan voor de bron van waarheid in de View-hiërarchie en @ObservedObject voor het injecteren van afhankelijkheden.
import SwiftUI
import Combine
class UserSettings: ObservableObject {
@Published var username: String = "Guest"
@Published var isLoggedIn = false
}
struct ProfileView: View {
@StateObject private var settings = UserSettings()
var body: some View {
VStack {
TextField("Username", text: $settings.username)
.textFieldStyle(.roundedBorder)
Toggle("Logged In", isOn: $settings.isLoggedIn)
if settings.isLoggedIn {
Text("Welkom, \(settings.username)!")
.font(.headline)
}
}
.padding()
}
}UserSettings — een ObservableObject met twee @Published-eigenschappen. ProfileView bezit het object via @StateObject. Wijziging van username of isLoggedIn tekent ProfileView automatisch opnieuw. @Published gebruikt Combine Publisher om SwiftUI op de hoogte te stellen van wijzigingen. Gebruik @ObservedObject om settings door te geven aan kind-Views:
Apple definieert vier niveaus van Data Flow in SwiftUI: @State (lokaal, value type), @Binding (tweerichtings), @StateObject/@ObservedObject (reference type met ObservableObject), @EnvironmentObject (globaal, injectie via omgeving). EnvironmentObject maakt het mogelijk gegevens door de hele View-hiërarchie te delen zonder expliciete overdracht in de initialisator. Daarnaast werkt @AppStorage met UserDefaults, @SceneStorage — met scène-toestand, @FetchRequest — met Core Data. De keuze van het Data Flow-niveau bepaalt de architectuur van de applicatie: eenvoudige schermen gebruiken State/Binding, modulaire — ObservedObject, grootschalige — EnvironmentObject + Redux-achtige oplossingen (TCA, Composable Architecture).
| Property Wrapper | Eigendom | Type | Wanneer gebruiken |
|---|---|---|---|
| @State | Lokaal | Value (struct, enum) | Eenvoudige toestand van één View (teller, toggle, tekstveld) |
| @Binding | Extern | Verwijzing naar State | Kind-View dat gegevens van ouder wijzigt |
| @StateObject | View-bezit | Reference (class) | Bron van waarheid voor complex gegevensmodel |
| @ObservedObject | Injectie | Reference (class) | Model buiten View gemaakt (doorgegeven via init) |
| @EnvironmentObject | Globaal | Reference (class) | Gegevens toegankelijk voor hele hiërarchie (authenticatie, thema) |
Veelgestelde vragen
@State — voor value types (struct, enum, String, Int) en lokale toestand van één View. SwiftUI beheert het geheugen van State automatisch. @StateObject — voor reference types (class) die voldoen aan ObservableObject. @StateObject bezit het object en tekent de View opnieuw bij @Published-eigenschapswijzigingen. Gebruik @State voor eenvoudige tellers; voor modellen met logica — @StateObject.
Ja, SwiftUI integreert met UIKit via UIHostingController (SwiftUI binnen UIKit) en UIViewRepresentable (UIKit binnen SwiftUI). UIHostingController wikkelt een SwiftUI View in een UIViewController. UIViewRepresentable maakt het mogelijk UIKit-componenten (MKMapView, WKWebView) in SwiftUI te gebruiken. Dit is de standaardaanpak voor migratie van projecten van UIKit naar SwiftUI.
ViewBuilder — een result builder (Swift 5.1) die een set Views transformeert naar één waarde van het type TupleView, Group of ConditionalContent. ViewBuilder maakt het mogelijk imperatieve if/else en switch binnen een declaratieve body te schrijven. Zonder ViewBuilder zou voor elk conditioneel blok AnyView of Group moeten worden geretourneerd. ViewBuilder is de reden waarom in body geen komma tussen Views nodig is.
Ja, SwiftUI ondersteunt iOS 13+, iPadOS 13+, macOS 10.15+, watchOS 6+, tvOS 13+ en visionOS 1+. Sommige API's zijn echter alleen beschikbaar op nieuwere versies: bijvoorbeeld navigationStack (iOS 16+), Observable macro (iOS 17+). Gebruik #available en UIKit-aanpassingen voor achterwaartse compatibiliteit.
Xcode Debug View Hierarchy toont de SwiftUI View-boom met modificatoren en frames. Het hulpprogramma SwiftUI Inspector (rechterpaneel van Xcode) maakt het mogelijk modificatoren in real-time te wijzigen. self._printChanges() in body logt de oorzaken van hertekening. Instruments met het SwiftUI-sjabloon traceert View-prestaties en detecteert overmatige hertekeningen.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook