@ObservedObject egy property wrapper a SwiftUI-ban, amely lehetővé teszi a View számára, hogy megfigyelje a hierarchia más helyén létrehozott ObservableObject változásait. A @StateObject-tól eltérően az @ObservedObject nem hoz létre objektumot — csak feliratkozik annak objectWillChange publisher-ére és újrarajzolja a View-t a @Published tulajdonságok frissítésekor. Ez teszi az @ObservedObject-et a megfelelő választássá azok számára a gyermek View-k számára, amelyek az inicializátoron keresztül kapnak adatokat a szülőtől. Paul Hudson — Hacking with Swift (2025) cikke szerint a tipikus SwiftUI alkalmazás architektúrája a következőképpen épül fel: a gyökér View @StateObject-t használ a view model létrehozásához, és minden gyermek View @ObservedObject-en keresztül kapja meg, ami egyetlen igazságforrást biztosít adatduplikáció nélkül.
Főbb pontok
@ObservedObject egy property wrapper, amely feliratkoztatja a View-t az ObservableObject változásaira. Amikor az @ObservedObject-tel jelölt objektum megváltoztatja bármelyik @Published-tel deklarált tulajdonságát, a SwiftUI automatikusan újrarajzolja a View-t. Az @ObservedObject nem hoz létre objektumot — csak kapcsolatot létesít egy meglévő ObservableObject példány és a View között, amelynek reagálnia kell a változásaira.
A legfontosabb különbség az @ObservedObject és a @StateObject között — a tulajdonjog. Az @ObservedObject feltételezi, hogy az objektum a View hierarchiában magasabb szinten lett létrehozva és tárolva. A gyermek View egy referenciát kap erre az objektumra az inicializátoron keresztül, és egyszerűen megfigyeli azt. Ha a gyermek View újra létrejön, ugyanazt a referenciát kapja a szülőtől — az adatok nem vesznek el.
Az Apple Developer Documentation — SwiftUI (2025) szerint az @ObservedObject iOS 13-tól elérhető, ami az egyetlen lehetőséggé teszi az ObservableObject megfigyelésére olyan projektekben, amelyek támogatják a régi iOS verziókat. iOS 14+ esetén a @StateObject előnyösebb objektumok létrehozására, de az @ObservedObject továbbra is releváns a meglévő objektumok átadására.
Az @ObservedObject mechanizmusa a Combine keretrendszer ObservableObject protokollján alapul. Minden ObservableObject-nek megfelelő osztály automatikusan kap egy objectWillChange publisher-t, amely jelet küld bármely @Published tulajdonság megváltozása előtt. A SwiftUI @ObservedObject-en keresztül feliratkozik erre a publisher-re, és a jel vételakor a View-t újrarajzolandónak jelöli.
class TaskViewModel: ObservableObject {
@Published var tasks: [Task] = []
@Published var isLoading = false
func loadTasks() async {
isLoading = true
// adatok lekérése
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() }
}
}
Amikor a szülő View átadja a viewModel-t a TaskListView-nak az inicializátoron keresztül, a SwiftUI kapcsolatot hoz létre az objektum és a View között. A tasks tömb vagy az isLoading jelző megváltozásakor a SwiftUI újrarajzolja a TaskListView-t. Az objektum eközben változatlan marad — a szülő View-ban tárolódik @StateObject-en keresztül.
A különbség az @ObservedObject és a @StateObject között — a különbség a megfigyelő és a tulajdonos között. A @StateObject létrehozza az objektumot és kezeli annak életciklusát. Az @ObservedObject csak megfigyeli az objektumot, amely máshol lett létrehozva és tárolva. A választás közöttük a View adatokért való felelőssége alapján történik.
| Forgatókönyv | Ajánlás | Ok |
|---|---|---|
| View adatokat hoz létre | @StateObject | View birtokolja az objektumot és felelős az életciklusáért |
| View adatokat kap | @ObservedObject | View csak megfigyeli, az objektum a szülőben él |
| iOS 13 támogatás | @ObservedObject | @StateObject nem elérhető, használjon @ObservedObject-et kézi kezeléssel |
| Újrafelhasználható komponens | @ObservedObject | A komponens nem hozhat létre adatokat — kívülről kapja |
Fő szabály: ha a View objektumot hoz létre — @StateObject. Ha a View objektumot fogad — @ObservedObject. Ennek a szabálynak a megsértése az @ObservedObject irányába objektum létrehozásakor adatvesztéshez vezet a View újraépítésekor. A megsértés a @StateObject irányába objektum fogadásakor duplikált példányt hoz létre, amely független a szülőtől.
Az @ObservedObject tipikus használati forgatókönyve — egy feladatlista, ahol a gyökér View létrehoz egy view model-t, és a lista cellája @ObservedObject-en keresztül kapja meg. Minden cella meghívhatja a view model metódusait, és a változások automatikusan megjelennek a teljes listában, mivel minden cella ugyanazt az objektumot figyeli.
struct TaskRow: View {
@ObservedObject var viewModel: TaskViewModel
let task: Task
var body: some View {
HStack {
Text(task.title)
Spacer()
Button("Kész") {
viewModel.completeTask(task)
}
}
}
}
struct TaskListContainer: View {
@StateObject var viewModel = TaskViewModel()
var body: some View {
List(viewModel.tasks) { task in
TaskRow(viewModel: viewModel, task: task)
}
}
}
Ebben a példában a TaskListContainer @StateObject-en keresztül hozza létre a viewModel-t, és minden TaskRow @ObservedObject-en keresztül kapja meg. Amikor a felhasználó „Done” gombra kattint bármelyik sorban, a viewModel.completeTask megváltoztatja a published tulajdonságot, és az összes View, amely ezt az objektumot figyeli, automatikusan frissül.
A leggyakoribb hiba — az @ObservedObject használata objektum létrehozására a View-n belül. Amikor a View újraépül (pl. állapotváltozáskor), a SwiftUI új ObservableObject példányt hoz létre, ami az összes felhalmozott adat elvesztéséhez vezet. Ez a hiba különösen fájdalmas a NavigationStack-ben, ahol a felhasználó kitölthet egy űrlapot, és a visszalépéskor elveszítheti az adatokat.
// ❌ Adatvesztés: az @ObservedObject nem tartja meg az objektumot
struct FormView: View {
@ObservedObject var formVM = FormViewModel()
// Új formVM létrehozva minden View újraépítéskor!
}
// ✅ Helyes: a @StateObject megtartja az objektumot
struct FormView: View {
@StateObject var formVM = FormViewModel()
// Objektum egyszer létrehozva a View élettartama alatt
}
Ha a gyermek View ugyanazt az ObservableObject-et @StateObject-en keresztül deklarálja, független másolatot hoz létre. A szülő objektumban végzett változtatások nem lesznek láthatóak a gyermekben és fordítva. Mindig @ObservedObject-et használjon azokhoz a gyermek View-khoz, amelyek kívülről kapják az objektumot.
A modern SwiftUI-ban több alternatíva is létezik az @ObservedObject helyett, mindegyiknek megvannak a maga előnyei. A választás az alkalmazás architektúrájától, az iOS verziótól és a konkrét használati forgatókönyvtől függ.
A választás az @ObservedObject és a @EnvironmentObject között — stílus és architektúra kérdése. Az @ObservedObject explicit módon mutatja a View függőségeit az inicializátoron keresztül, ami kiszámíthatóbbá teszi a kódot. A @EnvironmentObject mély hierarchiákhoz kényelmes, de elrejti a függőségeket, ami megnehezítheti a hibakeresést.
Gyakran Ismételt Kérdések
Igen, ha az objektum a SwiftUI-n kívül jött létre és tárolódik — például az AppDelegate-ben vagy singleton-ban. Ebben az esetben az @ObservedObject egyszerűen feliratkozik a meglévő objektum változásaira. Azonban a SwiftUI hierarchián belül létrehozott objektumokhoz mindig szükség van egy @StateObject-re valahol feljebb.
A legvalószínűbb ok — a tulajdonság nem @Published-en keresztül változik, vagy nem maga az objektum változik, hanem annak belső szerkezete az objectWillChange meghívása nélkül. Gyűjteményekhez használjon új másolat hozzárendelését: array.append() nem elegendő — a teljes tömböt újra hozzá kell rendelni array = array + [element] segítségével.
Az @ObservedObject önmagában nem okoz jelentős terhelést. Problémák akkor merülnek fel, ha gyakran változnak a @Published tulajdonságok — minden változás az összes megfigyelő View újrarajzolását indítja el. Optimalizáláshoz használjon EquatableView-t, csökkentse a published tulajdonságok számát és kerülje a felesleges frissítéseket.
@ObservedObject az egész ObservableObject osztályt figyeli, és újrarajzolja a View-t a published tulajdonságainak bármilyen változásakor. @Binding kétirányú kapcsolatot hoz létre egy adott értékkel (String, Int, Bool) és lehetővé teszi annak olvasását és írását. A @Binding könnyebb és nem igényel ObservableObject-et.
Igen, ez egy szabványos minta. Az ObservableObject-en belüli @Published automatikusan integrálódik az @ObservedObject-val. Minden @Published tulajdonság hozzáad egy megfigyelőt az objectWillChange publisher-hez. Bármelyikük változásakor az összes @ObservedObject-val rendelkező View ehhez az objektumhoz újrarajzolódik.
Összegzés
Kulcsrakész mobilalkalmazást fejlesztünk
Az IT Sectr 2017 óta készít iOS és Android alkalmazásokat induló vállalkozásoknak és vállalkozásoknak. Tanácsot adunk, és a legjobb megoldást javasoljuk.
Olvassa el is