Το @State είναι ένα Property Wrapper στο SwiftUI για τη διαχείριση τοπικής κατάστασης μέσα σε ένα όραμα. Το SwiftUI ανασχεδιάζει αυτόματα το όραμα σε κάθε αλλαγή της ιδιότητας @State, κάνοντας τη διεπαφή αντιδραστική χωρίς χειροκίνητες κλήσεις ενημέρωσης. Σύμφωνα με το Apple Developer Documentation (2025), το @State συνιστάται για απλούς τύπους και δομές που ανήκουν σε ένα όραμα. @State είναι ο απλούστερος τρόπος να προσθέσετε διαδραστικότητα σε μια διεπαφή SwiftUI.
Κύρια σημεία
@State είναι ένα ενσωματωμένο Property Wrapper στο SwiftUI που επιτρέπει σε ένα όραμα να αποθηκεύει και να παρακολουθεί τη δική του κατάσταση. Όταν η τιμή του @State αλλάζει, το SwiftUI ανασχεδιάζει αυτόματα το όραμα, καλώντας ξανά την ιδιότητα body. Αυτή είναι η βάση του αντιδραστικού προγραμματισμού στο SwiftUI: ο προγραμματιστής δηλώνει την κατάσταση και το πλαίσιο αναλαμβάνει τον συγχρονισμό της διεπαφής.
Το @State δημιουργεί μια περιοχή αποθήκευσης στο σωρό που διαχειρίζεται το SwiftUI. Αυτή η περιοχή είναι μόνιμη — επιβιώνει από επαναλαμβανόμενες αρχικοποιήσεις της δομής του οράματος που συμβαίνουν σε κάθε απόδοση. Το SwiftUI χρησιμοποιεί το αναγνωριστικό του οράματος (που δημιουργείται με βάση τη θέση στην ιεραρχία) για να συνδέσει την ιδιότητα @State με ένα συγκεκριμένο όραμα. Χάρη σε αυτό, η κατάσταση δεν επαναφέρεται κατά την ενημέρωση του γονικού οράματος.
Σημαντικός περιορισμός: το @State προορίζεται μόνο για τύπους τιμής (δομές, απαριθμήσεις, πρωτόγονα). Για τύπους αναφοράς (κλάσεις) χρησιμοποιήστε @StateObject ή @ObservedObject. Εάν αντιστοιχίσετε μια κλάση σε μια ιδιότητα @State, το SwiftUI δεν θα μπορεί να ανιχνεύσει αλλαγές μέσα στο αντικείμενο — μόνο την αντικατάσταση ολόκληρης της αναφοράς.
Το SwiftUI υλοποιεί το @State μέσω του εσωτερικού μηχανισμού Storage. Κάθε ιδιότητα @State λαμβάνει ένα αποκλειστικό κελί μνήμης που αποθηκεύεται στο ειδικό κοντέινερ αποθήκευσης του οράματος. Όταν συμβαίνει εγγραφή στο wrappedValue, το SwiftUI μέσω του didSet ειδοποιεί το γράφημα εξαρτήσεών του (dependency graph) για την ανάγκη ανασχεδιασμού.
struct ContentView: View {
@State private var name: String = "User"
@State private var isLoggedIn: Bool = false
var body: some View {
VStack {
Text("Γεια σου, \(name)")
Button(isLoggedIn ? "Αποσύνδεση" : "Σύνδεση") {
isLoggedIn.toggle()
}
}
}
}
Στο παράδειγμα υπάρχουν δύο ιδιότητες @State: name (String) και isLoggedIn (Bool). Κατά την κλήση του isLoggedIn.toggle(), το SwiftUI σημειώνει το ContentView ως απαιτούν ενημέρωση και επανεκτελεί το body στον επόμενο κύκλο απόδοσης. Βασικό σημείο: οι ιδιότητες @State δηλώνονται πάντα με τον τροποποιητή private — αυτό είναι ένα σήμα ότι η κατάσταση ανήκει αποκλειστικά στο τρέχον όραμα και δεν πρέπει να αλλάζεται από έξω άμεσα.
Για την παρατήρηση αλλαγών, το SwiftUI χρησιμοποιεί το CurrentValueSubject από το Combine. Κάθε ιδιότητα @State δημιουργεί έναν κρυφό εκδότη που ειδοποιεί το σύστημα σε κάθε αλλαγή. Αυτό επιτρέπει στο SwiftUI να ανασχεδιάζει μόνο το ελάχιστα απαραίτητο σύνολο οραμάτων, αποφεύγοντας την πλήρη ενημέρωση της ιεραρχίας.
Το @State είναι βέλτιστο για απλές τοπικές καταστάσεις: πεδία κειμένου αναζήτησης, boolean σημαίες για modal παράθυρα, διακόπτες ρυθμίσεων, μετρητές, επιλεγμένα στοιχεία λίστας. Εάν η τιμή χρησιμοποιείται μόνο σε ένα όραμα και στα ένθετα στοιχεία του (μέσω @Binding), το @State είναι η σωστή επιλογή. Για καταστάσεις που πρέπει να επιβιώσουν από το κλείσιμο του οράματος (π.χ. δεδομένα φόρμας), το @State είναι επίσης κατάλληλο όσο το όραμα παραμένει στην ιεραρχία.
Μην χρησιμοποιείτε το @State για καθολικές καταστάσεις εφαρμογής, προσωρινή αποθήκευση δεδομένων δικτύου ή αντικειμένων που χρησιμοποιούνται σε πολλές οθόνες. Για αυτούς τους σκοπούς προορίζονται τα @StateObject και @EnvironmentObject. Επίσης, το @State δεν είναι κατάλληλο για αποθήκευση μεγάλου όγκου δεδομένων — κάθε φορά που αλλάζει, ολόκληρο το όραμα θα ανασχεδιάζεται.
@Binding είναι μια γέφυρα μεταξύ του @State στο γονικό όραμα και του θυγατρικού οράματος που πρέπει να αλλάξει αυτήν την κατάσταση. Ο γονέας δηλώνει το @State και το θυγατρικό στοιχείο λαμβάνει το Binding μέσω της προβολής $. Η αλλαγή του Binding στο θυγατρικό όραμα ενημερώνει αυτόματα το @State στον γονέα — και αντίστροφα. Αυτό εξασφαλίζει μονόδρομη ροή δεδομένων με δυνατότητα ανάδρασης.
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)
}
}
Στη λίστα, το ParentView κατέχει το @State text, και το ChildView λαμβάνει το $text ως Binding. Το TextField μέσα στο ChildView συνδέεται με αυτό το Binding μέσω του text: $text. Όταν ο χρήστης πληκτρολογεί στο TextField, η τιμή αλλάζει στο ChildView μέσω του Binding, προκαλώντας ενημέρωση του @State στο ParentView. Και τα δύο οράματα ανασχεδιάζονται με τη νέα τιμή.
Το πιο συνηθισμένο λάθος — αντιστοίχιση κλάσης σε μια ιδιότητα @State. Εάν γράψετε @State var model = MyClass(), το SwiftUI δεν θα μπορεί να παρακολουθήσει αλλαγές ιδιοτήτων μέσα στην κλάση — μόνο την αντικατάσταση του ίδιου του αντικειμένου. Για κλάσεις χρησιμοποιείτε πάντα @StateObject. Το δεύτερο συνηθισμένο πρόβλημα — δήλωση του @State χωρίς τον τροποποιητή private, που παραβιάζει την αρχή ενθυλάκωσης της κατάστασης.
Άμεση μεταβίβαση του @State σε θυγατρικό όραμα χωρίς $ — άλλο ένα τυπικό λάθος. Εάν μεταβιβάσετε TextField(text: text) αντί για TextField(text: $text), το θυγατρικό στοιχείο θα λάβει ένα απλό string, όχι Binding. Η αλλαγή κειμένου στο TextField δεν θα συγχρονιστεί με το γονικό @State. Χρησιμοποιείτε πάντα την προβολή $ για τη μεταβίβαση Binding.
Το τρίτο λάθος — πολλαπλές ιδιότητες @State για συσχετιζόμενα δεδομένα. Εάν πολλές τιμές λογικά αποτελούν ένα ενιαίο σύνολο (π.χ. πεδία φόρμας), συνδυάστε τις σε μία δομή με ένα μόνο @State. Αυτό απλοποιεί τη μεταβίβαση κατάστασης σε θυγατρικά οράματα και μειώνει τον αριθμό ξεχωριστών ενεργοποιητών ενημέρωσης.
@State χρησιμοποιείται στα περισσότερα έργα SwiftUI για βασική διαδραστικότητα. Ας εξετάσουμε ένα παράδειγμα φόρμας σύνδεσης, όπου το @State διαχειρίζεται τα πεδία κειμένου και την κατάσταση φόρτωσης. Αυτό το μοτίβο συναντάται σε κάθε εφαρμογή — από απλές σημειώσεις έως πολύπλοκες εταιρικές λύσεις.
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("Σύνδεση") {
login()
}.disabled(isLoading)
}
}
private func login() {
isLoading = true
// Εκτέλεση αιτήματος δικτύου
}
}
Στο παράδειγμα υπάρχουν τέσσερις ιδιότητες @State: email και password για τα πεδία φόρμας, isLoading για ένδειξη φόρτωσης και errorMessage για εμφάνιση σφαλμάτων. Κάθε ιδιότητα διαχειρίζεται ανεξάρτητα το δικό της μέρος της διεπαφής. Όταν αλλάζει το isLoading, το κουμπί μπλοκάρεται αυτόματα μέσω του disabled(isLoading) — χωρίς χειροκίνητη ενημέρωση UI.
Συχνές ερωτήσεις
@State προορίζεται για την τοπική κατάσταση ενός συγκεκριμένου οράματος. Ο τροποποιητής private εγγυάται ότι άλλα στοιχεία δεν μπορούν να το αλλάξουν άμεσα, παραβιάζοντας την ενθυλάκωση. Για εξωτερική πρόσβαση χρησιμοποιήστε την προβολή $.
Ναι, το @State υποστηρίζει πίνακες και λεξικά, καθώς αυτά είναι τύποι τιμής. Ωστόσο, κατά την αλλαγή ενός στοιχείου πίνακα, το SwiftUI ανασχεδιάζει ολόκληρο το όραμα. Για μεγάλες λίστες, είναι πιο αποδοτικό να χρησιμοποιείτε @StateObject με @Published.
@State λειτουργεί σωστά με τύπους Optional. Κατά την αντιστοίχιση nil, το SwiftUI ανιχνεύει την αλλαγή και ανασχεδιάζει το όραμα. Αυτό είναι βολικό για καταστάσεις όπως errorMessage: String?, όπου το nil σημαίνει απουσία σφάλματος.
@State διατηρεί την τιμή όσο το όραμα παραμένει στην ιεραρχία. Εάν το όραμα αφαιρεθεί από την ιεραρχία και προστεθεί ξανά, το @State επαναρχικοποιείται με την προεπιλεγμένη τιμή. Για μονιμότητα χρησιμοποιήστε @AppStorage.
Ναι, τυλίξτε την αλλαγή σε withAnimation: withAnimation(.easeInOut) { isExpanded.toggle() }. Το SwiftUI κάνει κίνησης τη μετάβαση μεταξύ παλιάς και νέας κατάστασης της διεπαφής με τον καθορισμένο τύπο κίνησης.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης