@State este un Property Wrapper în SwiftUI pentru gestionarea stării locale în cadrul unei singure vederi. SwiftUI redesenează automat vederea la fiecare modificare a proprietății @State, făcând interfața reactivă fără apeluri manuale de actualizare. Potrivit Apple Developer Documentation (2025), @State este recomandat pentru tipuri simple și structuri aparținând unei singure vederi. @State este cel mai simplu mod de a adăuga interactivitate într-o interfață SwiftUI.
Principalele puncte
@State este un Property Wrapper încorporat în SwiftUI care permite unei vederi să stocheze și să urmărească propria stare. Când valoarea @State se modifică, SwiftUI redesenează automat vederea, re-apelând proprietatea body. Aceasta este baza programării reactive în SwiftUI: dezvoltatorul declară starea, iar framework-ul preia sincronizarea interfeței.
@State creează o zonă de stocare în heap gestionată de SwiftUI. Această zonă este persistentă — supraviețuiește inițializărilor repetate ale structurii vederii care au loc la fiecare randare. SwiftUI folosește identificatorul vederii (generat pe baza poziției în ierarhie) pentru a lega proprietatea @State de o anumită vedere. Datorită acestui fapt, starea nu se resetează la actualizarea vederii părinte.
O limitare importantă: @State este destinat doar tipurilor-valoare (structuri, enumerări, primitive). Pentru tipurile de referință (clase) utilizați @StateObject sau @ObservedObject. Dacă atribuiți o clasă unei proprietăți @State, SwiftUI nu va putea detecta modificările din interiorul obiectului — doar înlocuirea întregii referințe.
SwiftUI implementează @State prin mecanismul intern Storage. Fiecare proprietate @State primește o celulă de memorie dedicată stocată în containerul special de stocare al vederii. Când are loc o scriere în wrappedValue, SwiftUI prin didSet notifică graful său de dependențe (dependency graph) despre necesitatea redesenării.
struct ContentView: View {
@State private var name: String = "User"
@State private var isLoggedIn: Bool = false
var body: some View {
VStack {
Text("Salut, \(name)")
Button(isLoggedIn ? "Deconectare" : "Autentificare") {
isLoggedIn.toggle()
}
}
}
}
În exemplu sunt două proprietăți @State: name (String) și isLoggedIn (Bool). La apelarea isLoggedIn.toggle(), SwiftUI marchează ContentView ca necesitând actualizare și reexecută body în următorul ciclu de randare. Punctul cheie: proprietățile @State se declară întotdeauna cu modificatorul private — acesta este un semnal că starea aparține exclusiv vederii curente și nu trebuie modificată din exterior direct.
Pentru observarea modificărilor, SwiftUI folosește CurrentValueSubject din Combine. Fiecare proprietate @State creează un editor ascuns care notifică sistemul la fiecare modificare. Acest lucru permite SwiftUI să redeseneze doar setul minim necesar de vederi, evitând actualizarea completă a ierarhiei.
@State este optim pentru stări locale simple: câmpuri de text pentru căutare, fanioane booleene pentru ferestre modale, comutatoare de setări, contoare, elemente selectate din listă. Dacă valoarea este utilizată doar într-o singură vedere și componentele sale imbricate (prin @Binding), @State este alegerea corectă. Pentru stări care ar trebui să supraviețuiască închiderii vederii (de exemplu, datele unui formular), @State este de asemenea potrivit, atâta timp cât vederea rămâne în ierarhie.
Nu utilizați @State pentru stări globale ale aplicației, stocarea în cache a datelor de rețea sau obiecte utilizate în mai multe ecrane. În aceste scopuri sunt destinate @StateObject și @EnvironmentObject. De asemenea, @State nu este potrivit pentru stocarea unor volume mari de date — de fiecare dată când se modifică, întreaga vedere va fi redesenată.
@Binding este o punte între @State din vederea părinte și vederea copil care trebuie să modifice această stare. Părintele declară @State, iar componentul copil primește Binding prin proiecția $. Modificarea Binding-ului în vederea copil actualizează automat @State-ul din părinte — și invers. Aceasta asigură un flux unidirecțional de date cu posibilitate de feedback.
struct ParentView: View {
@State private var text: String = ""
var body: some View {
ChildView(text: $text)
}
}
struct ChildView: View {
@Binding var text: String
var body: some View {
TextField("Enter text", text: $text)
}
}
În listare, ParentView deține @State text, iar ChildView primește $text ca Binding. TextField-ul din interiorul ChildView se leagă de acest Binding prin text: $text. Când utilizatorul tastează în TextField, valoarea se modifică în ChildView prin Binding, ceea ce provoacă actualizarea @State-ului în ParentView. Ambele vederi se redesenează cu noua valoare.
Cea mai frecventă greșeală — atribuirea unei clase unei proprietăți @State. Dacă scrieți @State var model = MyClass(), SwiftUI nu va putea urmări modificările proprietăților din interiorul clasei — doar înlocuirea obiectului în sine. Pentru clase utilizați întotdeauna @StateObject. A doua problemă comună — declararea @State fără modificatorul private, ceea ce încalcă principiul încapsulării stării.
Transmiterea directă a @State către o vedere copil fără $ — încă o greșeală tipică. Dacă transmiteți TextField(text: text) în loc de TextField(text: $text), componentul copil va primi un simplu string, nu un Binding. Modificarea textului în TextField nu va fi sincronizată cu @State-ul părinte. Folosiți întotdeauna proiecția $ pentru a transmite Binding.
A treia greșeală — proprietăți @State multiple pentru date conexe. Dacă mai multe valori formează logic un întreg unic (de exemplu, câmpurile unui formular), combinați-le într-o singură structură cu un singur @State. Aceasta simplifică transmiterea stării către vederile copil și reduce numărul de declanșatoare de actualizare separate.
@State este utilizat în majoritatea proiectelor SwiftUI pentru interactivitatea de bază. Să examinăm un exemplu de formular de autentificare, unde @State gestionează câmpurile text și starea de încărcare. Acest model se întâlnește în fiecare aplicație — de la notițe simple la soluții corporative complexe.
struct LoginView: View {
@State private var email: String = ""
@State private var password: String = ""
@State private var isLoading: Bool = false
@State private var errorMessage: String?
var body: some View {
Form {
TextField("Email", text: $email)
SecureField("Password", text: $password)
Button("Autentificare") {
login()
}.disabled(isLoading)
}
}
private func login() {
isLoading = true
// Efectuează cerere de rețea
}
}
În exemplu sunt patru proprietăți @State: email și password pentru câmpurile formularului, isLoading pentru indicarea încărcării și errorMessage pentru afișarea erorilor. Fiecare proprietate gestionează independent propria parte a interfeței. La modificarea isLoading, butonul se blochează automat prin disabled(isLoading) — fără actualizare manuală a UI-ului.
Întrebări frecvente
@State este destinat stării locale a unei anumite vederi. Modificatorul private garantează că alte componente nu îl pot modifica direct, încălcând încapsularea. Pentru acces extern utilizați proiecția $.
Da, @State suportă array-uri și dicționare, deoarece acestea sunt tipuri-valoare. Cu toate acestea, la modificarea unui element al array-ului, SwiftUI redesenează întreaga vedere. Pentru liste mari, este mai eficient să utilizați @StateObject cu @Published.
@State funcționează corect cu tipurile Optional. La atribuirea nil, SwiftUI detectează modificarea și redesenează vederea. Acest lucru este convenabil pentru stări precum errorMessage: String?, unde nil înseamnă absența unei erori.
@State păstrează valoarea atâta timp cât vederea rămâne în ierarhie. Dacă vederea este eliminată din ierarhie și adăugată din nou, @State se reinițializează cu valoarea implicită. Pentru persistență utilizați @AppStorage.
Da, înfășurați modificarea în withAnimation: withAnimation(.easeInOut) { isExpanded.toggle() }. SwiftUI animează tranziția între starea veche și cea nouă a interfeței cu tipul de animație specificat.
Rezumat
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.
Citiți și