@ObservedObject är en property wrapper i SwiftUI som gör att en View kan observera ändringar i ett ObservableObject som skapats på en annan plats i hierarkin. Till skillnad från @StateObject skapar @ObservedObject inte ett objekt — det prenumererar bara på dess publisher objectWillChange och ritar om View vid uppdatering av @Published-egenskaper. Detta gör @ObservedObject till rtt val för underordnade Views som tar emot data från föräldern via initieraren. Enligt Paul Hudsons artikel — Hacking with Swift (2025) byggs en typisk SwiftUI-applikationsarkitektur upp så här: rotvyn använder @StateObject för att skapa en view model och alla underordnade Views tar emot den via @ObservedObject, vilket ger en enda källa till sanning utan dataduplicering.
Huvudpunkter
@ObservedObject är en property wrapper som prenumererar en View på ObservableObject-ändringar. När ett objekt markerat med @ObservedObject ändrar någon av sina egenskaper deklarerade med @Published, ritar SwiftUI automatiskt om vyn. @ObservedObject skapar inte objektet — det etablerar bara en anslutning mellan en befintlig ObservableObject-instans och den View som ska reagera på dess ändringar.
Den viktigaste skillnaden mellan @ObservedObject och @StateObject — är ägande. @ObservedObject förutsätter att objektet har skapats och lagrats någonstans högre upp i View-hierarkin. Den underordnade vyn får en referens till detta objekt via initieraren och observerar det bara. Om den underordnade vyn återskapas får den samma referens från föräldern — data går inte förlorad.
Enligt Apple Developer Documentation — SwiftUI (2025) är @ObservedObject tillgängligt från iOS 13, vilket gör det till det enda alternativet för att observera ObservableObject i projekt som stödjer äldre iOS-versioner. I iOS 14+ föredras @StateObject för att skapa objekt, men @ObservedObject förblir relevant för att överföra befintliga objekt.
Mekanismen för @ObservedObject är baserad på ObservableObject-protokollet från Combine-ramverket. Varje klass som är kompatibel med ObservableObject får automatiskt en publisher objectWillChange som skickar en signal innan någon @Published-egenskap ändras. SwiftUI prenumererar på denna publisher via @ObservedObject och vid mottagning av signalen markerar vyn som att den kräver omritning.
class TaskViewModel: ObservableObject {
@Published var tasks: [Task] = []
@Published var isLoading = false
func loadTasks() async {
isLoading = true
// hämta data
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() }
}
}
När den överordnade vyn överför viewModel till TaskListView via initieraren, skapar SwiftUI en anslutning mellan objektet och vyn. Vid ändring av tasks-arrayen eller isLoading-flaggan ritar SwiftUI om TaskListView. Objektet förblir oförändrat — det lagras i den överordnade vyn via @StateObject.
Skillnaden mellan @ObservedObject och @StateObject — är skillnaden mellan observatör och ägare. @StateObject skapar objektet och hanterar dess livscykel. @ObservedObject observerar bara objektet som har skapats och lagrats på en annan plats. Valet mellan dem bestäms av vymens ansvar för data.
| Scenario | Rekommendation | Anledning |
|---|---|---|
| View skapar data | @StateObject | View äger objektet och är ansvarig för dess livscykel |
| View tar emot data | @ObservedObject | View observerar bara, objektet lever i föräldern |
| Stöd för iOS 13 | @ObservedObject | @StateObject inte tillgängligt, använd @ObservedObject med manuell hantering |
| Återanvändbar komponent | @ObservedObject | Komponenten bör inte skapa data — den tar emot den utifrån |
Huvudregel: om View skapar ett objekt — @StateObject. Om View tar emot ett objekt — @ObservedObject. Brott mot denna regel till förmån för @ObservedObject för att skapa objekt leder till dataförlust vid ombyggnad av vyn. Brott till förmån för @StateObject för att ta emot objekt skapar en duplicerad instans, oberoende av föräldern.
Ett typiskt användningsscenario för @ObservedObject — en uppgiftslista, där rotvyn skapar en view model och listcellen tar emot den via @ObservedObject. Varje cell kan anropa metoder i view model och ändringarna visas automatiskt i hela listan, eftersom alla celler observerar samma objekt.
struct TaskRow: View {
@ObservedObject var viewModel: TaskViewModel
let task: Task
var body: some View {
HStack {
Text(task.title)
Spacer()
Button("Klart") {
viewModel.completeTask(task)
}
}
}
}
struct TaskListContainer: View {
@StateObject var viewModel = TaskViewModel()
var body: some View {
List(viewModel.tasks) { task in
TaskRow(viewModel: viewModel, task: task)
}
}
}
I detta exempel skapar TaskListContainer viewModel via @StateObject och varje TaskRow tar emot den via @ObservedObject. När användaren klickar på „Done” i någon rad, ändrar viewModel.completeTask den publicerade egenskapen och alla Views som observerar detta objekt uppdateras automatiskt.
Det vanligaste misstaget — att använda @ObservedObject för att skapa ett objekt inuti vyn. När vyn byggs om (t.ex. vid ändring av state), skapar SwiftUI en ny ObservableObject-instans, vilket leder till förlust av all ackumulerad data. Detta misstag är särskilt smärtsamt i NavigationStack, där en användare kan fylla i ett formulär och förlora data vid återgång.
// ❌ Dataförlust: @ObservedObject behåller inte objektet
struct FormView: View {
@ObservedObject var formVM = FormViewModel()
// Ny formVM skapas vid varje ombyggnad av View!
}
// ✅ Korrekt: @StateObject behåller objektet
struct FormView: View {
@StateObject var formVM = FormViewModel()
// Objekt skapat en gång under vymens livstid
}
Om en underordnad View deklarerar samma ObservableObject via @StateObject, skapar den en oberoende kopia. Ändringar i det överordnade objektet syns inte i det underordnade och vice versa. Använd alltid @ObservedObject för underordnade Views som tar emot objektet utifrån.
I modern SwiftUI finns flera alternativ till @ObservedObject, var och en med sina fördelar. Valet beror på applikationsarkitekturen, iOS-versionen och det specifika användningsscenariot.
Valet mellan @ObservedObject och @EnvironmentObject — är en fråga om stil och arkitektur. @ObservedObject visar explicit vymens beroenden via initieraren, vilket gör koden mer förutsägbar. @EnvironmentObject är bekvämt för djupa hierarkier men döljer beroenden, vilket kan försvåra felsökning.
Vanliga frågor
Ja, om objektet skapas och lagras utanför SwiftUI — till exempel i AppDelegate eller singleton. I detta fall prenumererar @ObservedObject bara på ändringarna av det befintliga objektet. För objekt som skapas inom SwiftUI-hierarkin behövs dock alltid en @StateObject någonstans högre upp.
Den mest sannolika orsaken — egenskapen ändras inte via @Published eller så ändras inte själva objektet, utan dess interna struktur utan anrop av objectWillChange. För samlingar, använd tilldelning av en ny kopia: array.append() räcker inte — hela arrayen måste tilldelas på nytt via array = array + [element].
@ObservedObject i sig skapar ingen betydande belastning. Problem uppstår vid freventa ändringar av @Published-egenskaper — varje ändring utlöser omritning av alla observerande Views. För optimering, använd EquatableView, minska antalet publicerade egenskaper och undvik onödiga uppdateringar.
@ObservedObject observerar hela ObservableObject-klassen och ritar om vyn vid varje ändring av dess publicerade egenskaper. @Binding skapar en tvåvägsanslutning med ett specifikt värde (String, Int, Bool) och möjliggör läsning och skrivning. @Binding är lättare och kräver inget ObservableObject.
Ja, detta är ett standardmönster. @Published inuti ObservableObject integreras automatiskt med @ObservedObject. Varje @Published-egenskap lägger till en observatör till objectWillChange-publishern. När någon av dem ändras, ritas alla Views med @ObservedObject för detta objekt om.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också