Το @ObservedObject είναι ένα Property Wrapper στο SwiftUI για την παρατήρηση μιας παρουσίας ObservableObject που μεταβιβάζεται από έξω. Σε αντίθεση με το @StateObject, το @ObservedObject δεν δημιουργεί αντικείμενο — εγγράφεται στις αλλαγές ενός υπάρχοντος. Σύμφωνα με το Apple Developer Documentation (2025), το @ObservedObject χρησιμοποιείται σε θυγατρικά view που πρέπει να παρακολουθούν δεδομένα που ανήκουν στον γονέα. @ObservedObject παρέχει αντιδραστική σύνδεση χωρίς διαχείριση του κύκλου ζωής του αντικειμένου.
Βασικά Σημεία
@ObservedObject είναι ένα Property Wrapper που εγγράφει το view στις αλλαγές του ObservableObject. Το ObservableObject είναι ένα πρωτόκολλο από το πλαίσιο Combine που απαιτεί την υλοποίηση του publisher objectWillChange. Όταν οποιαδήποτε ιδιότητα με την ένδειξη @Published αλλάζει εντός του ObservableObject, ο publisher στέλνει ένα σήμα και το SwiftUI επανασχεδιάζει όλα τα view που είναι εγγεγραμμένα μέσω @ObservedObject.
Το κύριο χαρακτηριστικό του @ObservedObject είναι η απουσία ιδιοκτησίας. Το view δεν είναι υπεύθυνο για τη δημιουργία ή την καταστροφή του αντικειμένου. Το αντικείμενο δημιουργείται στο γονικό view (μέσω @StateObject) ή εισάγεται μέσω @EnvironmentObject. Το θυγατρικό view μόνο παρατηρεί αλλαγές και λαμβάνει ενημερώσεις. Εάν το αντικείμενο αντικατασταθεί στον γονέα, το @ObservedObject μεταβαίνει στη νέα παρουσία.
Το @ObservedObject είναι κατάλληλο για σενάρια κοινής χρήσης δεδομένων: μοντέλο χρήστη, κοινές ρυθμίσεις, κατάσταση σύνδεσης με τον διακομιστή. Όταν πολλαπλά view σε διαφορετικά επίπεδα της ιεραρχίας πρέπει να εμφανίζουν τα ίδια δεδομένα, το @ObservedObject σε κάθε view δημιουργεί ανεξάρτητες αλλά συντονισμένες εγγραφές σε μία πηγή.
Η διαφορά μεταξύ @ObservedObject και @StateObject είναι ένα από τα πιο συνηθισμένα θέματα ερωτήσεων σε συνεντεύξεις SwiftUI. Ο βασικός κανόνας: το @StateObject δημιουργεί και κατέχει το αντικείμενο, το @ObservedObject παρατηρεί ένα υπάρχον. Η παραβίαση αυτού του κανόνα οδηγεί σε απροσδόκητη απώλεια δεδομένων ή διπλή αρχικοποίηση.
| Χαρακτηριστικό | @StateObject | @ObservedObject |
|---|---|---|
| Δημιουργία αντικειμένου | Ναι, κατά την αρχικοποίηση του view | Όχι, λαμβάνει έτοιμο |
| Ιδιοκτησία | Τρέχον view | Γονικό στοιχείο |
| Μοναδική παρουσία | Ναι, σε όλο τον κύκλο ζωής | Όχι, μπορεί να αντικατασταθεί |
| Επαναδημιουργία κατά την απόδοση | Όχι, διατηρείται | Εξαρτάται από τον γονέα |
| Πού να χρησιμοποιείται | Ριζικό view-ιδιοκτήτης | Θυγατρικά view |
@StateObject εγγυάται ότι το αντικείμενο δημιουργείται μία φορά και επιβιώνει από επαναλαμβανόμενες αρχικοποιήσεις της δομής view. Το @ObservedObject λαμβάνει το αντικείμενο από έξω και αναδημιουργείται σε κάθε αρχικοποίηση της γονικής δομής. Εάν ο γονέας χρησιμοποιεί @StateObject για το αντικείμενο, τα θυγατρικά view μπορούν να εφαρμόσουν με ασφάλεια το @ObservedObject — το αντικείμενο θα είναι μοναδικό σε ολόκληρη την ιεραρχία.
Ο μηχανισμός παρακολούθησης του @ObservedObject βασίζεται στο Combine και στο πρωτόκολλο ObservableObject. Κατά την αρχικοποίηση, το SwiftUI καλεί τον publisher objectWillChange — το αντικείμενο πρέπει να εκπέμψει σήμα πριν από την αλλαγή της @Published ιδιότητας. Το Combine μεταδίδει το σήμα στο γράφημα εξαρτήσεων του SwiftUI, το οποίο επισημαίνει όλα τα εξαρτώμενα view ως απαιτούντα ενημέρωση. Αυτό συμβαίνει σύγχρονα πριν από την αλλαγή της τιμής.
class WeatherService: ObservableObject {
@Published var temperature: Double = 22.0
@Published var city: String = "Moscow"
}
struct WeatherView: View {
@ObservedObject var weather: WeatherService
var body: some View {
VStack {
Text("\\(weather.city)")
Text("\\(weather.temperature)°C")
}
}
}
Στη λίστα, το WeatherService είναι ένα ObservableObject με δύο @Published ιδιότητες. Το WeatherView δηλώνει @ObservedObject var weather: WeatherService, λαμβάνοντας την παρουσία από τον γονέα. Όταν η temperature αλλάζει, το objectWillChange ενεργοποιείται πριν από τον ορισμό της νέας τιμής, το SwiftUI επανασχεδιάζει το WeatherView και εμφανίζεται η τρέχουσα θερμοκρασία. Η εγγραφή διαχειρίζεται αυτόματα από το SwiftUI — ο προγραμματιστής δεν χρειάζεται να καλέσει sink ή dispose.
Πρώτο μοτίβο — μεταβίβαση μοντέλου μέσω αρχικοποιητή. Ο γονέας δημιουργεί το ObservableObject μέσω @StateObject και το μεταβιβάζει στα θυγατρικά view ως @ObservedObject. Πρόκειται για μια τυπική ιεραρχική μεταφορά δεδομένων όπου το ριζικό view διαχειρίζεται τον κύκλο ζωής του μοντέλου και όλα τα ένθετα στοιχεία εγγράφονται στις αλλαγές.
Δεύτερο μοτίβο — EnvironmentObject, η καθολική έκδοση του @ObservedObject μέσω του SwiftUI Environment. Το αντικείμενο εισάγεται σε επίπεδο σκηνής ή ριζικού view και είναι αυτόματα διαθέσιμο σε όλα τα θυγατρικά στοιχεία χωρίς ρητή μεταβίβαση μέσω αρχικοποιητών. Μέσα στο θυγατρικό view, το @EnvironmentObject λειτουργεί παρόμοια με το @ObservedObject, αλλά λαμβάνει το αντικείμενο από το περιβάλλον.
Τρίτο μοτίβο — σύνθεση πολλαπλών ObservableObject. Σε σύνθετες εφαρμογές, το view μπορεί να παρατηρεί πολλαπλά αντικείμενα: @ObservedObject var user: UserService, @ObservedObject var network: NetworkMonitor. Αυτό διαχωρίζει την ευθύνη μεταξύ υπηρεσιών και διατηρεί τη δυνατότητα δοκιμής κάθε στοιχείου.
struct DashboardView: View {
@ObservedObject var user: UserViewModel
@ObservedObject var network: NetworkMonitor
var body: some View {
VStack {
Text("Καλώς ορίσατε, \\(user.name)")
HStack {
Circle()
.fill(network.isConnected ? Color.green : Color.red)
.frame(width: 10, height: 10)
}
}
}
}
DashboardView παρατηρεί το UserViewModel και το NetworkMonitor. Κάθε αντικείμενο είναι υπεύθυνο για τον δικό του τομέα δεδομένων και ειδοποιεί ανεξάρτητα το view για αλλαγές. Εάν το δίκτυο αποσυνδεθεί, το NetworkMonitor αλλάζει το isConnected και το SwiftUI επανασχεδιάζει το DashboardView, ενημερώνοντας το χρώμα του δείκτη. Η σύνθεση ObservableObject είναι ο προτιμώμενος τρόπος οργάνωσης δεδομένων σε εφαρμογές SwiftUI.
@Published είναι ένα Property Wrapper από το Combine που προσθέτει αυτόματα έναν εκδότη σε μια ιδιότητα εντός του ObservableObject. Όταν η @Published ιδιότητα αλλάζει, το Combine δημιουργεί ένα συμβάν μέσω του publisher objectWillChange. Το SwiftUI εγγράφεται σε αυτόν τον publisher όταν χρησιμοποιεί @ObservedObject ή @StateObject και επανασχεδιάζει το view σε κάθε νέα τιμή.
Το @Published υποστηρίζει όλους τους τύπους, συμπεριλαμβανομένων των προαιρετικών, συλλογών και προσαρμοσμένων δομών. Ωστόσο, για συλλογές (πίνακες, λεξικά) το SwiftUI παρακολουθεί μόνο την αντικατάσταση της αναφοράς, όχι την αλλαγή περιεχομένου. Για να εντοπίσετε την προσθήκη ή αφαίρεση ενός στοιχείου, πρέπει να επαναναθέσετε ολόκληρη τη συλλογή ή να χρησιμοποιήσετε ObservableObject με μη αυτόματη κλήση objectWillChange.send().
Σημαντική λεπτομέρεια: @Published πρέπει να βρίσκεται μόνο εντός μιας κλάσης που υλοποιεί το ObservableObject. Η χρήση @Published εκτός ObservableObject θα προκαλέσει σφάλμα μεταγλώττισης. Επίσης, το @Published δεν μπορεί να εφαρμοστεί σε ιδιότητες τεμπέλικης αρχικοποίησης (lazy var) ή υπολογιζόμενες ιδιότητες (computed property).
Το πιο κρίσιμο λάθος — η χρήση @ObservedObject για τη δημιουργία αντικειμένου. Εάν γράψετε @ObservedObject var model = UserViewModel() στο γονικό view, σε κάθε απόδοση θα δημιουργείται μια νέα παρουσία UserViewModel. Τα δεδομένα θα χαθούν και οι @Published εγγραφές θα αναδημιουργηθούν. Χρησιμοποιείτε πάντα @StateObject για δημιουργία και @ObservedObject μόνο για λήψη έτοιμου αντικειμένου.
Δεύτερο λάθος — αλλαγή @Published ιδιοτήτων εκτός του κύριου νήματος. Το ObservableObject χρησιμοποιεί το Combine, το οποίο απαιτεί την αποστολή αλλαγών στο κύριο νήμα (main actor). Εάν αλλάξετε το @Published σε μια ουρά παρασκηνίου, το SwiftUI μπορεί να επανασχεδιάσει το view σε ακατάλληλη στιγμή, προκαλώντας race conditions. Χρησιμοποιήστε DispatchQueue.main.async ή @MainActor για ενημέρωση.
Τρίτο πρόβλημα — κυκλικές ενημερώσεις. Εάν μια αλλαγή @Published περιλαμβάνει παρενέργειες που αλλάζουν ξανά το @Published, δημιουργείται ένας ατελείωτος βρόχος επανασχεδίασης. Λύση: χρησιμοποιήστε σημαίες προστασίας (isUpdating) ή διαχωρίστε τη λογική σε διαφορετικά ObservableObject με σαφή όρια ευθύνης.
Συχνές Ερωτήσεις
Ναι, το SwiftUI υποστηρίζει @ObservedObject var model: UserViewModel?. Ωστόσο, το view δεν θα εγγράφεται σε αλλαγές όσο το αντικείμενο είναι nil. Κατά την ανάθεση τιμής, η εγγραφή ενεργοποιείται αυτόματα.
@ObservedObject λαμβάνει το αντικείμενο μέσω αρχικοποιητή, @EnvironmentObject μέσω SwiftUI Environment. Το @EnvironmentObject δεν απαιτεί ρητή μεταβίβαση μέσω κατασκευαστών, αλλά το αντικείμενο πρέπει να εισαχθεί στο ανώτερο επίπεδο της ιεραρχίας.
Καλέστε το objectWillChange.send() πριν από την αλλαγή της ιδιότητας. Αυτό είναι χρήσιμο εάν το @Published δεν είναι κατάλληλο (για παράδειγμα, για υπολογιζόμενες ιδιότητες ή λειτουργίες συλλογών όπου η αλλαγή πρέπει να αναφερθεί πριν από τη μετάλλαξη).
@ObservedObject και @Published παρακολουθούν την αντικατάσταση της αναφοράς, όχι τη μετάλλαξη του περιεχομένου της συλλογής. Για επανασχεδίαση πρέπει να επαναναθέσετε τον πίνακα: items.append(newItem) → items = items ή να χρησιμοποιήσετε objectWillChange.send() πριν από τη μετάλλαξη.
Όχι, το @ObservedObject είναι ένα SwiftUI Property Wrapper διαθέσιμο μόνο εντός τύπων που υλοποιούν το πρωτόκολλο View. Για συνηθισμένες δομές, χρησιμοποιήστε το Combine απευθείας με το ObservableObjectPublisher.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης