@ObservedObject este un property wrapper în SwiftUI care permite unui View să observe modificările într-un ObservableObject creat în altă parte a ierarhiei. Spre deosebire de @StateObject, @ObservedObject nu creează un obiect — el doar se abonează la publisher-ul objectWillChange al acestuia și redesenează View-ul la actualizarea proprietăților @Published. Acest lucru face ca @ObservedObject să fie alegerea corectă pentru View-urile copil care primesc date de la părinte prin inițializator. Conform articolului lui Paul Hudson — Hacking with Swift (2025), arhitectura tipică a unei aplicații SwiftUI este construită astfel: View-ul rădăcină folosește @StateObject pentru a crea un view model, iar toate View-urile copil îl primesc prin @ObservedObject, asigurând o singură sursă de adevăr fără duplicare a datelor.
Principalele puncte
@ObservedObject este un property wrapper care abonează View-ul la modificările ObservableObject. Când obiectul marcat cu @ObservedObject modifică oricare dintre proprietățile sale declarate cu @Published, SwiftUI redesenează automat View-ul. @ObservedObject nu creează obiectul — el doar stabilește o conexiune între o instanță existentă ObservableObject și View-ul care trebuie să reacționeze la modificările sale.
Diferența cheie între @ObservedObject și @StateObject — este proprietatea. @ObservedObject presupune că obiectul a fost creat și stocat undeva mai sus în ierarhia View-urilor. View-ul copil primește o referință la acest obiect prin inițializator și pur și simplu îl observă. Dacă View-ul copil este recreat, va primi aceeași referință de la părinte — datele nu se pierd.
Conform Apple Developer Documentation — SwiftUI (2025), @ObservedObject este disponibil începând cu iOS 13, ceea ce îl face singura opțiune pentru observarea ObservableObject în proiecte care suportă versiuni vechi de iOS. În iOS 14+ este preferat @StateObject pentru crearea obiectelor, dar @ObservedObject rămâne relevant pentru transmiterea obiectelor existente.
Mecanismul @ObservedObject se bazează pe protocolul ObservableObject din framework-ul Combine. Fiecare clasă conformă cu ObservableObject primește automat un publisher objectWillChange care trimite un semnal înainte de modificarea oricărei proprietăți @Published. SwiftUI se abonează la acest publisher prin @ObservedObject și la primirea semnalului marchează View-ul ca necesitând redesenare.
class TaskViewModel: ObservableObject {
@Published var tasks: [Task] = []
@Published var isLoading = false
func loadTasks() async {
isLoading = true
// încărcare date
isLoading = false
}
}
struct TaskListView: View {
@ObservedObject var viewModel: TaskViewModel
var body: some View {
List(viewModel.tasks) { task in
Text(task.title)
}
.task { await viewModel.loadTasks() }
}
}
Când View-ul părinte transmite viewModel către TaskListView prin inițializator, SwiftUI creează o conexiune între obiect și View. La modificarea array-ului tasks sau a flag-ului isLoading, SwiftUI redesenează TaskListView. Obiectul rămâne neschimbat — este stocat în View-ul părinte prin @StateObject.
Diferența între @ObservedObject și @StateObject — este diferența între observator și proprietar. @StateObject creează obiectul și gestionează ciclul său de viață. @ObservedObject doar observă obiectul care a fost creat și stocat în altă parte. Alegerea între ele este determinată de responsabilitatea View-ului pentru date.
| Scenariu | Recomandare | Motiv |
|---|---|---|
| View-ul creează date | @StateObject | View-ul deține obiectul și răspunde de ciclul său de viață |
| View-ul primește date | @ObservedObject | View-ul doar observă, obiectul trăiește în părinte |
| Suport iOS 13 | @ObservedObject | @StateObject indisponibil, utilizați @ObservedObject cu gestionare manuală |
| Component reutilizabil | @ObservedObject | Componentul nu ar trebui să creeze date — le primește din exterior |
Regula principală: dacă View-ul creează obiectul — @StateObject. Dacă View-ul primește obiectul — @ObservedObject. Încălcarea acestei reguli în favoarea @ObservedObject pentru crearea obiectului duce la pierderea datelor la reconstruirea View-ului. Încălcarea în favoarea @StateObject pentru primirea obiectului creează o instanță duplicată, independentă de părinte.
Scenariul tipic de utilizare a @ObservedObject — o listă de sarcini, unde View-ul rădăcină creează un view model, iar celula listei îl primește prin @ObservedObject. Fiecare celulă poate apela metodele view model-ului, iar modificările sunt afișate automat în întreaga listă, deoarece toate celulele observă același obiect.
struct TaskRow: View {
@ObservedObject var viewModel: TaskViewModel
let task: Task
var body: some View {
HStack {
Text(task.title)
Spacer()
Button("Gata") {
viewModel.completeTask(task)
}
}
}
}
struct TaskListContainer: View {
@StateObject var viewModel = TaskViewModel()
var body: some View {
List(viewModel.tasks) { task in
TaskRow(viewModel: viewModel, task: task)
}
}
}
În acest exemplu TaskListContainer creează viewModel prin @StateObject, iar fiecare TaskRow îl primește prin @ObservedObject. Când utilizatorul apasă „Done” în orice rând, viewModel.completeTask modifică proprietatea published, iar toate View-urile care observă acest obiect se actualizează automat.
Cea mai frecventă eroare — utilizarea @ObservedObject pentru a crea un obiect în interiorul View-ului. Când View-ul este reconstruit (de exemplu, la modificarea stării), SwiftUI creează o nouă instanță ObservableObject, ceea ce duce la pierderea tuturor datelor acumulate. Această eroare este deosebit de dureroasă în NavigationStack, unde utilizatorul poate completa un formular și pierde datele la întoarcere.
// ❌ Pierdere de date: @ObservedObject nu reține obiectul
struct FormView: View {
@ObservedObject var formVM = FormViewModel()
// FormVM nou creat la fiecare reconstruire a View-ului!
}
// ✅ Corect: @StateObject reține obiectul
struct FormView: View {
@StateObject var formVM = FormViewModel()
// Obiect creat o dată pe durata de viață a View-ului
}
Dacă View-ul copil declară același ObservableObject prin @StateObject, creează o copie independentă. Modificările în obiectul părinte nu vor fi vizibile în copil și invers. Folosiți întotdeauna @ObservedObject pentru View-urile copil care primesc obiectul din exterior.
În SwiftUI modern există mai multe alternative la @ObservedObject, fiecare cu avantajele sale. Alegerea depinde de arhitectura aplicației, versiunea iOS și scenariul specific de utilizare.
Alegerea între @ObservedObject și @EnvironmentObject — este o chestiune de stil și arhitectură. @ObservedObject arată explicit dependențele View-ului prin inițializator, ceea ce face codul mai previzibil. @EnvironmentObject este convenabil pentru ierarhii adânci, dar ascunde dependențele, ceea ce poate îngreuna depanarea.
Întrebări frecvente
Da, dacă obiectul este creat și stocat în afara SwiftUI — de exemplu, în AppDelegate sau singleton. În acest caz @ObservedObject pur și simplu se abonează la modificările obiectului existent. Cu toate acestea, pentru obiectele create în interiorul ierarhiei SwiftUI este întotdeauna necesar un @StateObject undeva mai sus.
Cea mai probabilă cauză — proprietatea este modificată nu prin @Published sau nu se modifică obiectul în sine, ci structura sa internă fără apelarea objectWillChange. Pentru colecții folosiți atribuirea unei noi copii: array.append() nu este suficient — trebuie să reatribuiți întregul array prin array = array + [element].
@ObservedObject în sine nu creează o sarcină semnificativă. Problemele apar la modificări frecvente ale proprietăților @Published — fiecare modificare declanșează redesenarea tuturor View-urilor observatoare. Pentru optimizare folosiți EquatableView, reduceți numărul de proprietăți published și evitați actualizările inutile.
@ObservedObject observă întreaga clasă ObservableObject și redesenează View-ul la orice modificare a proprietăților sale published. @Binding creează o conexiune bidirecțională cu o valoare specifică (String, Int, Bool) și permite citirea și scrierea acesteia. @Binding este mai ușor și nu necesită ObservableObject.
Da, acesta este un model standard. @Published în interiorul ObservableObject se integrează automat cu @ObservedObject. Fiecare proprietate @Published adaugă un observator la publisher-ul objectWillChange. La modificarea oricăreia dintre ele, toate View-urile cu @ObservedObject pentru acest obiect sunt redeseneate.
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