SwiftUI är ett deklarativt ramverk från Apple för att bygga användargränssnitt på alla plattformar i ekosystemet. Istället för att imperativt beskriva steg deklarerar utvecklaren hur gränssnittet ska se ut och SwiftUI hanterar rendering och uppdatering. Enligt Apple Developer Documentation (2025) stöder SwiftUI iOS 15+, iPadOS 15+, macOS 12+, watchOS 8+ och tvOS 15+ och använder View Protocol som grundläggande byggsten för alla gränssnittskomponenter.
Huvudpunkter
body — grunden för varje UI-komponent i SwiftUI som returnerar en skärmbeskrivning genom komposition av vyer.SwiftUI är ett deklarativt ramverk som introducerades av Apple 2019 för att ersätta UIKit i nya projekt. Istället för att manuellt skapa UIView-instanser och lägga till dem i hierarkin beskriver utvecklaren gränssnittet genom strukturer som implementerar View-protokollet. SwiftUI beräknar automatiskt skillnaden mellan nuvarande och nytt tillstånd och ritar endast om de ändrade delarna med hjälp av sin egen renderingsmotor.
Ramverket är skrivet i Swift med value semantics (strukturer, inte klasser), vilket gör UI-komponenter lätta och trådsäkra. Till skillnad från UIKit, där en UIViewController kan väga 200+ bytes på grund av Objective-C runtime, är en SwiftUI View bara en struktur på några bytes storlek. Detta är särskilt viktigt för watchOS med dess begränsade minne.
Samma View-beskrivning fungerar på iPhone, iPad, Mac, Apple Watch, Apple TV och Apple Vision Pro. SwiftUI anpassar gränssnittet efter plattformen: på iOS — tryckgester, på macOS — tangentbordsgenvägar, på watchOS — rullning med Digital Crown. Detta förkortar utvecklingstiden för företag som släpper appar på flera Apple-plattformar, men kräver ytterligare konfiguration för specifika element på varje plattform.
I SwiftUI är varje skärm en struktur som implementerar View-protokollet med ett enda krav: computed property body av typen some View. Nyckelordet some (opaque type) döljer den konkreta typen av vyn och låter SwiftUI optimera renderingen. Inuti body kombinerar utvecklaren färdiga komponenter — Text, Image, Button, List — med hjälp av ViewBuilder, som samlar flera vyer i en.
struct GreetingView: View {
let name: String
var var body: some View {
VStack {
Text("Hej, \(name)!")
.font(.title)
.foregroundColor(.blue)
Image(systemName: "hand.wave")
.imageScale(.large)
}
.padding()
}
}
I exemplet innehåller VStack (vertikal stack) Text och Image. Värdet name skickas via strukturens initierare — så fungerar DI (Dependency Injection) i SwiftUI utan externa DI-behållare. Varje modifierare returnerar en ny vy med den tillämpade ändringen utan att mutera original. Detta är möjligt tack vare oföränderligheten (immutability) hos värdetyper.
ViewBuilder är en result builder, annoterad med @resultBuilder, som samlar upp till 10 vyer i en. Inuti body kan if/else, switch och ForEach användas utan extra omslag. ForEach fungerar med Identifiable-element — varje vy får ett unikt id för korrekt animering vid insättning/borttagning.
I SwiftUI bestämmer tillståndet vilket innehåll som visas på skärmen. När tillståndet ändras återskapar SwiftUI body för den beroende vyn och jämför resultatet med det föregående med hjälp av diff-algoritmen. För lagring av tillstånd används property wrappers — var och en löser sin egen uppgift: lokalt tillstånd, koppling till en barnvy eller extern datamodell.
struct CounterView: View {
@State private var count = 0
var var body: some View {
VStack {
Text("Räknare: \(count)")
Button("Öka") {
count += 1
}
}
}
}
class UserViewModel: ObservableObject {
@Published var name = ""
@Published var age = 0
}
@State lagrar ett lokalt enkelt värde (Int, String, Bool) inuti View-strukturen. SwiftUI flyttar minnet från strukturen till en separat lagringsplats — därför kan egenskapen med @State ändras (muteras), även om View är en värdetyp. @ObservableObject — för klasser med @Published-egenskaper, vars ändringar automatiskt meddelar SwiftUI om behovet av omritning.
@Binding skapar en tvåvägsförbindelse med datakällan som finns i den överordnade vyn. Föräldern skickar $variable (projected value), barnet läser och skriver värdet via binding. Detta gör det möjligt att flytta textinmatning eller en strömbrytare till en separat komponent samtidigt som tillståndet behålls i föräldern. Utan @Binding skulle varje ändring kräva en callback-slutning för att skicka det nya värdet uppåt.
Före iOS 16 byggde navigeringen i SwiftUI på NavigationView — ett föråldrat API med komplext beteende på iPad (split view, double column). Från och med iOS 16 rekommenderar Apple NavigationStack — ett förenklat alternativ med typsäkra rutter. Utvecklaren definierar en enum över möjliga rutter och NavigationStack hanterar automatiskt skärmstacken med stöd för djupa länkar och återgång till roten.
enum Route: Hashable {
case detail(id: Int)
case settings
}
struct ContentView: View {
var var body: some View {
NavigationStack {
List {
NavigationLink("Detaljskärm",
value: Route.detail(id: 42))
NavigationLink("Inställningar",
value: Route.settings)
}
.navigationDestination(for: Route.self) { route in
switch route {
case .detail(let id): DetailView(id: id)
case .settings: SettingsView()
}
}
}
}
}
Rutter av typen Route: Hashable gör det möjligt att använda vilken datatyp som helst för att skicka parametrar. navigationDestination(for:destination:) kopplar ruttyp till målvyn. Fördelen jämfört med UIKit-navigering — omritning krävs inte när en ny rutt läggs till: det räcker att lägga till ett case i enum och en hanterare i switch. Djupa länkar bearbetas via processDeepLink på NavigationStack.
För programmatisk övergång (efter inloggning, timer eller serversvar) används @State med NavigationLink-initierare: NavigationLink(isActive: $isActive). När isActive = true ställs in sker övergången utan användarens beröring. Alternativ — bindning av arrayen $path i NavigationStack: $path.append(Route.detail(id: 1)).
Modifier är en metod som returnerar en modifierad kopia av vyn. Till skillnad från UIKit, där konfiguration av egenskaper görs genom mutation av den befintliga vyn, skapar SwiftUI ett nytt värde med den tillämpade ändringen. Kedjan av modifierare (chaining) bygger det slutliga gränssnittet från sekventiella transformationer: teckensnitt → mellanrum → färg → skugga → gest.
Apple tillhandahåller över 200 inbyggda modifierare. De vanligaste är: .font(), .foregroundColor(), .padding(), .background(), .cornerRadius(), .shadow(), .opacity(), .offset(). Ordningen på modifierarna är viktig: .padding() före .background() färgar området med mellanrum, efteråt — bara det inre området. Anpassade modifierare skapas via protokollet ViewModifier.
Modifierare kan tillämpas villkorligt via den ternära operatorn: .foregroundColor(isError ? .red : .primary). För animering används .animation(.easeInOut, value: state) — animeringsmodifieraren kopplas till en specifik egenskap hos tillståndet. När denna egenskap ändras animerar SwiftUI övergången mellan det gamla och nya värdet. Animering fungerar med opacity, offset, scale, rotation, storlek och färg — för varje egenskap definieras en motsvarande AnimatableParameter.
För anpassade animeringar finns .transition (visning/försvinnande) och .matchedGeometryEffect (smidig övergång av ett element mellan två behållare). Den senare används för hero-animering i listor: en ikon i en listcell förvandlas smidigt till en stor bild på detaljskärmen.
Valet mellan SwiftUI och UIKit är ett av de första dilemman för en iOS-utvecklare. Båda ramverken stöds av Apple, men löser uppgiften att bygga gränssnitt på fundamentalt olika sätt: SwiftUI deklarativt, UIKit imperativt. Skillnaden visar sig i tillståndshantering, navigering, prestanda och kompatibilitet.
| Aspekt | SwiftUI | UIKit |
|---|---|---|
| Tillvägagångssätt | Deklarativt: vad som ska visas | Imperativt: hur man bygger |
| Tillstånd | Property Wrappers, automatisk omritning | Manuellt: reloadData, setNeedsLayout |
| UI-kod | Kompakt, modifierarkedjor | Omfattande, NSCoder/Storyboard/begränsningar |
| Prestanda | Hög på iOS 17+, diff-algoritm | Topp på iOS 12–16, direkt kontroll |
| Minsta version | iOS 15+ (fullt stöd) | iOS 2+ (alla versioner) |
För nya projekt med minsta version iOS 17 rekommenderar Apple SwiftUI som primärt ramverk. UIKit förblir nödvändigt för gränssnitt som kräver fin kontroll över rendering (anpassad UICollectionViewLayout, komplexa CAAnimation-scener) eller stöd för iOS 12–14. Många projekt använder en hybridmetod: SwiftUI bäddas in via UIHostingController i en UIKit-app, och UIViewRepresentable möjliggör användning av UIKit-komponenter i SwiftUI-hierarkin.
Vanliga frågor
Ja, via UIHostingController (SwiftUI i UIKit) och UIViewRepresentable (UIKit i SwiftUI). Detta är en hybridmetod, populär vid migrering.
iOS 17 — full funktionalitet: NavigationStack, Observation framework, Swift Charts. iOS 15 — minsta tröskel för produktion.
Den vanligaste orsaken är ändring av en @Published-egenskap på en bakgrundstråd. ObservableObject måste skicka ändringar till main actor: @MainActor class ViewModel.
Använd .debounce via Combine: Button.publisher(for: .tap) .debounce(for: .seconds(0.3), scheduler: RunLoop.main).
Ja, via Gesture-modifierare: DragGesture, LongPressGesture, MagnificationGesture, RotationGesture. Kombinera dem via .simultaneousGesture() och .sequenced().
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också