SwiftUI — concepte cheie, View, State și Data Flow

Autor: IT Sectr Publicat: 2026-02-21 Timp de citire: 8 min

SwiftUI — framework-ul declarativ Apple pentru construirea interfețelor de utilizator pe toate platformele ecosistemului, prezentat la WWDC 2019. Spre deosebire de UIKit imperativ cu viewDidLoad și actualizarea manuală a ecranului, SwiftUI descrie UI ca o colecție de structuri simple conforme cu protocolul View. Conform Swift.org (2025), SwiftUI este utilizat în 65% din noile proiecte publicate în App Store. Framework-ul gestionează automat actualizarea interfeței prin mecanismul State și Data Flow — la modificarea datelor, View este redesenat fără apelarea manuală a reloadData.

Principalele

  • SwiftUI — framework-ul declarativ Apple pentru UI (2019), unde interfața este descrisă prin structuri conforme cu protocolul View.
  • View — blocul de bază al SwiftUI; fiecare View își descrie partea sa de ecran prin computed property body.
  • @State — property wrapper pentru stocarea stării locale, la a cărei modificare View se redesenează automat.
  • @Binding — legătura bidirecțională între View și date, permițând View-ului copil să modifice starea părintelui.
  • @ObservedObject și @StateObject — legătura cu modele externe de date prin clase conforme cu protocolul ObservableObject.

Ce este SwiftUI?

SwiftUI — framework-ul UI declarativ Apple, radical diferit de UIKit. În loc să creeze controlere, view-uri și să gestioneze manual ciclul lor de viață, dezvoltatorul descrie interfața sub formă de declarații: ce ar trebui să fie pe ecran, nu cum să fie construit. SwiftUI se bazează pe principiul reactivității: interfața este o funcție a stării. La modificarea stării (State), SwiftUI recalculează automat body-ul tuturor View-urilor dependente și actualizează doar părțile modificate ale ecranului. SwiftUI este disponibil pe iOS 13+, iPadOS 13+, macOS 10.15+, watchOS 6+, tvOS 13+ și visionOS 1+. Codul SwiftUI este cross-platform: un fișier funcționează pe iPhone, iPad, Mac și Apple Watch cu adaptări minime de platformă. Conform Apple WWDC Session 101 (2024), SwiftUI acoperă peste 90% din modelele UI standard ale App Store.

SwiftUI vs UIKit

UIKit — framework-ul imperativ (2008): dezvoltatorul creează UIViewController, configurează subviews în viewDidLoad, implementează delegate/datasource pentru UITableView și actualizează ecranul prin reloadData sau setNeedsLayout. SwiftUI înlocuiește controlerele cu structuri simple View, delegatele — cu binding și onChange, Auto Layout — cu HStack/VStack/ZStack și modificatori (padding, frame, offset). UIKit necesită gestionarea manuală a memoriei prin ARC; SwiftUI — structuri care nu necesită numărarea referințelor. Performanța SwiftUI este comparabilă cu UIKit: framework-ul folosește un algoritm de diffing pentru un set minim de modificări. În IT Sectr, SwiftUI este utilizat pentru proiecte noi cu target iOS 17+; proiectele cu suport iOS 14–15 necesită UIKit din cauza compatibilității limitate a SwiftUI.

Sintaxa declarativă SwiftUI

În SwiftUI, interfața este descrisă prin ViewBuilder — result builder care transformă un set de View într-un tuplu sau Group. Modificatorii (.padding(), .font(), .foregroundColor()) creează View-uri noi cu setări modificate, nu mută obiectul original. Fiecare modificator returnează un View nou, permițând înlănțuirea. ViewBuilder suportă if/else, switch, ForEach — randare condițională și ciclică fără controlere separate. View în SwiftUI este un value type (struct), ceea ce garantează un comportament previzibil și elimină race conditions.

Protocolul View și computed property body

View — protocol cu o singură cerință: computed property body de tip some View. Fiecare structură conformă cu View își descrie partea de ecran în body. Tipul some View — opaque return type care ascunde tipul concret al View-ului returnat (îmbinarea VStack, HStack, ZStack, Text, Image etc.). Compilatorul Swift deduce tipul concret în faza de compilare, păstrând performanța apelului direct fără ștergerea tipului.

swift
import SwiftUI

struct GreetingView: View {
    var name: String
    
    var body: some View {
        VStack(spacing: 12) {
            Text("Salut, \(name)!")
                .font(.largeTitle)
                .foregroundColor(.primary)
            
            Text("Bun venit în SwiftUI")
                .font(.body)
                .foregroundColor(.secondary)
        }
        .padding()
        .background(
            RoundedRectangle(cornerRadius: 12)
                .fill(.ultraThinMaterial)
        )
    }
}

Structura GreetingView primește parametrul name și afișează două blocuri de text într-un stack vertical. Modificatorii .font, .foregroundColor, .padding și .background configurează aspectul. SwiftUI apelează body de fiecare dată când parametrii de intrare (name) se modifică — redesenează doar părțile modificate. În exemplu se folosește RoundedRectangle cu .ultraThinMaterial — fundal nativ blur încorporat în SwiftUI.

@State: starea locală în SwiftUI

@State — property wrapper care declară starea locală aparținând unui singur View. SwiftUI gestionează automat memoria State: la modificarea valorii, body este redesenat, dar numai pentru View-urile care folosesc acest State. State este sursa de adevăr (source of truth) pentru tipuri simple (String, Int, Bool, enum). Nu folosiți @State pentru modele de date complexe — pentru ele sunt destinate @StateObject și @ObservedObject. State trebuie să fie private și stocat în View-ul însuși, nu transmis între componente.

swift
import SwiftUI

struct CounterView: View {
    @State private var count = 0
    
    var body: some View {
        VStack(spacing: 20) {
            Text("Numărătoare: \(count)")
                .font(.system(size: 48, weight: .bold))
            
            Button(action: { count += 1 }) {
                Label("Incrementează", systemImage: "plus.circle")
            }
            .buttonStyle(.borderedProminent)
        }
        .padding()
    }
}

Valoarea inițială count = 0. Fiecare apăsare a butonului incrementează count; SwiftUI redesenează automat CounterView complet (toate View-urile). În UIKit, un scenariu similar ar necesita IBOutlet, IBAction și actualizarea manuală a label.text. @State garantează că View-ul este redesenat doar la modificarea unui anumit State — algoritmul de diffing al SwiftUI găsește modificările minime în arbore.

@Binding: legătura bidirecțională între View

@Binding — property wrapper care creează o legătură bidirecțională între View și datele pe care View nu le deține. Binding este o referință la State (sau altă sursă de adevăr), permițând View-ului copil să citească și să modifice valoarea stocată în părinte. Binding se notează cu prefixul $: $count transmite Binding<Int> către View-ul copil. Fără Binding, View-ul copil nu poate modifica datele părintelui — poate doar să le citească.

swift
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 deține State quantity și transmite Binding prin $quantity. StepperControl poate modifica value, iar quantity în părinte se sincronizează automat. Binding nu este o copie a datelor, ci un pod către sursa de adevăr. Folosiți @Binding pentru controale personalizate, editoare și componente reutilizabile care trebuie să modifice datele părintelui.

@ObservedObject și @StateObject: modele externe de date

@StateObject — property wrapper pentru crearea și deținerea unei instanțe de clasă conformă cu ObservableObject. View-ul creează obiectul o dată pe ciclu de viață și se redesenează la modificarea proprietăților sale @Published. @ObservedObject — wrapper similar, dar View-ul nu deține obiectul — obiectul este creat și stocat în afara View-ului (transmis prin inițializator). Apple recomandă @StateObject pentru source of truth în ierarhia de View-uri și @ObservedObject pentru injectarea dependențelor.

swift
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("Bun venit, \(settings.username)!")
                    .font(.headline)
            }
        }
        .padding()
    }
}

UserSettings — ObservableObject cu două proprietăți @Published. ProfileView deține obiectul prin @StateObject. Modificarea username sau isLoggedIn redesenează automat ProfileView. @Published folosește Combine Publisher pentru a notifica SwiftUI despre modificări. Pentru a transmite settings View-urilor copil, folosiți @ObservedObject:

Data Flow în SwiftUI: imaginea completă

Apple definește patru niveluri de Data Flow în SwiftUI: @State (local, value type), @Binding (bidirecțional), @StateObject/@ObservedObject (reference type cu ObservableObject), @EnvironmentObject (global, injectat prin mediu). EnvironmentObject permite transmiterea datelor prin întreaga ierarhie View fără transmitere explicită în inițializator. Suplimentar, @AppStorage lucrează cu UserDefaults, @SceneStorage — cu starea scenei, @FetchRequest — cu Core Data. Alegerea nivelului de Data Flow determină arhitectura aplicației: ecranele simple folosesc State/Binding, modulele — ObservedObject, aplicațiile la scară largă — EnvironmentObject + soluții de tip Redux (TCA, Composable Architecture).

Property WrapperDeținereTipCând să folosiți
@StateLocalăValue (struct, enum)Stare simplă a unui View (contor, toggle, câmp text)
@BindingExternăReferință la StateView copil care modifică datele părintelui
@StateObjectDeținere ViewReference (class)Sursă de adevăr pentru model de date complex
@ObservedObjectInjectareReference (class)Model creat în afara View-ului (transmis prin init)
@EnvironmentObjectGlobalăReference (class)Date accesibile întregii ierarhii (autentificare, temă)

Întrebări frecvente

Cu ce diferă @State de @StateObject?

@State — pentru value types (struct, enum, String, Int) și starea locală a unui View. SwiftUI gestionează automat memoria State. @StateObject — pentru reference types (class) conforme cu ObservableObject. @StateObject deține obiectul și redesenează View-ul la modificarea proprietăților @Published. Pentru contoare simple folosiți @State; pentru modele cu logică — @StateObject.

Se poate folosi SwiftUI cu UIKit?

Da, SwiftUI se integrează cu UIKit prin UIHostingController (SwiftUI în interiorul UIKit) și UIViewRepresentable (UIKit în interiorul SwiftUI). UIHostingController înfășoară SwiftUI View într-un UIViewController. UIViewRepresentable permite utilizarea componentelor UIKit (MKMapView, WKWebView) în SwiftUI. Aceasta este abordarea standard pentru migrarea proiectelor de la UIKit la SwiftUI.

Ce este ViewBuilder în SwiftUI?

ViewBuilder — result builder (Swift 5.1) care transformă un set de View într-o singură valoare de tip TupleView, Group sau ConditionalContent. ViewBuilder permite scrierea de if/else și switch imperativ în interiorul body-ului declarativ. Fără ViewBuilder ar trebui să returnați AnyView sau Group pentru fiecare bloc condițional. ViewBuilder este motivul pentru care în body nu este nevoie de virgulă între View-uri.

SwiftUI funcționează pe toate dispozitivele Apple?

Da, SwiftUI suportă iOS 13+, iPadOS 13+, macOS 10.15+, watchOS 6+, tvOS 13+ și visionOS 1+. Totuși, unele API-uri sunt disponibile doar pe versiunile noi: de exemplu, navigationStack (iOS 16+), Observable macro (iOS 17+). Pentru compatibilitate inversă, folosiți #available și adaptări UIKit.

Cum se depanează aplicațiile SwiftUI?

Xcode Debug View Hierarchy arată arborele SwiftUI View cu modificatori și cadre. Instrumentul SwiftUI Inspector (panoul drept Xcode) permite modificarea modificatorilor în timp real. self._printChanges() în body jurnalizează cauzele redesemnării. Instruments cu șablonul SwiftUI urmărește performanța View și detectează redesemnări excesive.

Rezumat

  • SwiftUI — framework-ul declarativ Apple pentru UI, unde interfața este descrisă prin structuri View cu computed property body (2019).
  • View — value type (struct) conform cu protocolul View; body returnează some View prin ViewBuilder.
  • @State — stare locală pentru value types; la modificare, View se redesenează automat.
  • @Binding — legătură bidirecțională prin prefixul $; View-ul copil modifică datele părintelui.
  • @StateObject / @ObservedObject — reference types cu ObservableObject și proprietăți @Published; StateObject deține obiectul, ObservedObject îl primește din exterior.
  • @EnvironmentObject — stare globală pentru întreaga ierarhie View; injectat prin .environmentObject().
  • Data Flow în SwiftUI — de la State (local) prin Binding (bidirecțional) la ObservedObject (modular) și EnvironmentObject (global).

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și