@ObservedObject: co to jest, obserwacja obiektów i aktualizacja View

Autor: IT Sectr Opublikowano: 2026-06-26 Czas czytania: 9 min

@ObservedObject — to property wrapper w SwiftUI, który pozwala View obserwować zmiany w ObservableObject utworzonym w innym miejscu hierarchii. W przeciwieństwie do @StateObject, @ObservedObject nie tworzy obiektu — on tylko subskrybuje jego publisher objectWillChange i przerysowuje View przy aktualizacji właściwości @Published. To czyni @ObservedObject właściwym wyborem dla podrzędnych View, które otrzymują dane od rodzica przez inicjalizator. Według artykułu Paul Hudson — Hacking with Swift (2025), typowa architektura aplikacji SwiftUI wygląda następująco: główny View używa @StateObject do utworzenia view model, a wszystkie podrzędne View otrzymują go przez @ObservedObject, co zapewnia jeden źródło prawdy bez duplikowania danych.

Najważniejsze

  • @ObservedObject — property wrapper do obserwacji ObservableObject utworzonego w nadrzędnym View.
  • Nie posiada obiektu — w przeciwieństwie do @StateObject, @ObservedObject nie zarządza cyklem życia obiektu.
  • Subskrypcja zmian — przy zmianie właściwości @Published View automatycznie się przerysowuje.
  • Przekazanie przez inicjalizator — obiekt jest przekazywany do podrzędnego View przez parametr inicjalizatora.
  • iOS 13+ — @ObservedObject jest dostępny od pierwszej wersji SwiftUI, w przeciwieństwie do @StateObject (iOS 14+).

Co to jest @ObservedObject w SwiftUI

@ObservedObject — to property wrapper, który subskrybuje View do zmian ObservableObject. Gdy obiekt oznaczony @ObservedObject zmienia którąkolwiek ze swoich właściwości zadeklarowanych z @Published, SwiftUI automatycznie przerysowuje View. @ObservedObject nie tworzy obiektu — on jedynie ustanawia połączenie między już istniejącym egzemplarzem ObservableObject a View, które ma reagować na jego zmiany.

Kluczowa różnica między @ObservedObject a @StateObject — to własność. @ObservedObject zakłada, że obiekt został utworzony i przechowywany gdzieś wyżej w hierarchii View. Podrzędne View otrzymuje referencję do tego obiektu przez inicjalizator i po prostu go obserwuje. Jeśli podrzędne View zostanie odtworzone, otrzyma tę samą referencję od rodzica — dane nie zostaną utracone.

Według Apple Developer Documentation — SwiftUI (2025), @ObservedObject jest dostępny od iOS 13, co czyni go jedyną opcją do obserwacji ObservableObject w projektach obsługujących starsze wersje iOS. W iOS 14+ preferowany jest @StateObject do tworzenia obiektów, ale @ObservedObject pozostaje aktualny do przekazywania istniejących obiektów.

Jak działa @ObservedObject

Mechanizm @ObservedObject opiera się na protokole ObservableObject z frameworka Combine. Każda klasa zgodna z ObservableObject automatycznie otrzymuje publisher objectWillChange, który wysyła sygnał przed zmianą dowolnej właściwości @Published. SwiftUI subskrybuje tego publishera przez @ObservedObject i po otrzymaniu sygnału oznacza View jako wymagające przerysowania.

swift
class TaskViewModel: ObservableObject {
    @Published var tasks: [Task] = []
    @Published var isLoading = false
    
    func loadTasks() async {
        isLoading = true
        // pobierz dane
        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() }
    }
}

Gdy nadrzędne View przekazuje viewModel do TaskListView przez inicjalizator, SwiftUI tworzy połączenie między obiektem a View. Przy zmianie tablicy tasks lub flagi isLoading SwiftUI przerysowuje TaskListView. Obiekt pozostaje przy tym niezmieniony — jest przechowywany w nadrzędnym View przez @StateObject.

@ObservedObject vs @StateObject: kiedy czego używać

Różnica między @ObservedObject a @StateObject — to różnica między obserwatorem a właścicielem. @StateObject tworzy obiekt i zarządza jego cyklem życia. @ObservedObject tylko obserwuje obiekt, który został utworzony i przechowywany w innym miejscu. Wybór między nimi jest określony przez odpowiedzialność View za dane.

ScenariuszZaleceniePrzyczyna
View tworzy dane@StateObjectView posiada obiekt i odpowiada za jego cykl życia
View otrzymuje dane@ObservedObjectView tylko obserwuje, obiekt żyje w rodzicu
Wsparcie iOS 13@ObservedObject@StateObject niedostępny, użyj @ObservedObject z ręcznym zarządzaniem
Komponent wielokrotnego użytku@ObservedObjectKomponent nie powinien tworzyć danych — otrzymuje je z zewnątrz

Główna zasada: jeśli View tworzy obiekt — @StateObject. Jeśli View przyjmuje obiekt — @ObservedObject. Naruszenie tej zasady w stronę @ObservedObject do tworzenia obiektu prowadzi do utraty danych przy odbudowie View. Naruszenie w stronę @StateObject do przyjmowania obiektu tworzy zduplikowany egzemplarz, niezależny od nadrzędnego.

Przykłady użycia @ObservedObject

Typowy scenariusz użycia @ObservedObject — lista zadań, gdzie główne View tworzy view model, a komórka listy otrzymuje go przez @ObservedObject. Każda komórka może wywoływać metody view modelu, a zmiany są automatycznie wyświetlane na całej liście, ponieważ wszystkie komórki obserwują ten sam obiekt.

swift
struct TaskRow: View {
    @ObservedObject var viewModel: TaskViewModel
    let task: Task
    
    var body: some View {
        HStack {
            Text(task.title)
            Spacer()
            Button("Gotowe") {
                viewModel.completeTask(task)
            }
        }
    }
}

struct TaskListContainer: View {
    @StateObject var viewModel = TaskViewModel()
    
    var body: some View {
        List(viewModel.tasks) { task in
            TaskRow(viewModel: viewModel, task: task)
        }
    }
}

W tym przykładzie TaskListContainer tworzy viewModel przez @StateObject, a każda TaskRow otrzymuje go przez @ObservedObject. Gdy użytkownik kliknie „Done” w dowolnym wierszu, viewModel.completeTask zmienia właściwość published, a wszystkie View obserwujące ten obiekt aktualizują się automatycznie.

Typowe błędy z @ObservedObject

Najczęstszy błąd — użycie @ObservedObject do tworzenia obiektu wewnątrz View. Gdy View jest odbudowywane (np. przy zmianie state), SwiftUI tworzy nowy egzemplarz ObservableObject, co prowadzi do utraty wszystkich zgromadzonych danych. Ten błąd jest szczególnie dotkliwy w NavigationStack, gdzie użytkownik może wypełnić formularz i stracić dane przy powrocie.

Błąd: @ObservedObject zamiast @StateObject

swift
// ❌ Utrata danych: @ObservedObject nie przechowuje obiektu
struct FormView: View {
    @ObservedObject var formVM = FormViewModel()
    // Nowy formVM tworzony przy każdej odbudowie View!
}

// ✅ Poprawnie: @StateObject przechowuje obiekt
struct FormView: View {
    @StateObject var formVM = FormViewModel()
    // Obiekt utworzony raz na czas życia View
}

Błąd: przekazanie @StateObject tam, gdzie potrzebny @ObservedObject

Jeśli podrzędne View deklaruje ten sam ObservableObject przez @StateObject, tworzy niezależną kopię. Zmiany w nadrzędnym obiekcie nie będą widoczne w podrzędnym i odwrotnie. Zawsze używaj @ObservedObject dla podrzędnych View, które otrzymują obiekt z zewnątrz.

Alternatywy dla @ObservedObject w SwiftUI

We współczesnym SwiftUI istnieje kilka alternatyw dla @ObservedObject, każda z własnymi zaletami. Wybór zależy od architektury aplikacji, wersji iOS i konkretnego scenariusza użycia.

  • @EnvironmentObject — pozwala uzyskać obiekt ze środowiska SwiftUI bez jawnego przekazywania przez inicjalizator. Wygodny dla obiektów potrzebnych na wielu ekranach, ale wymaga jawnego wstrzyknięcia przez .environmentObject().
  • @State + @Binding — dla prostych typów wartościowych nie są potrzebne ObservableObject. Użyj @State do przechowywania i @Binding do przekazywania do podrzędnych View.
  • @AppStorage — dla wartości UserDefaults, które powinny automatycznie synchronizować się z View.
  • @SceneStorage — do zapisywania tymczasowego stanu między restartami sceny (np. pozycja na liście).

Wybór między @ObservedObject a @EnvironmentObject — to kwestia stylu i architektury. @ObservedObject jawnie pokazuje zależności View przez inicjalizator, co czyni kod bardziej przewidywalnym. @EnvironmentObject jest wygodny dla głębokich hierarchii, ale ukrywa zależności, co może utrudnić debugowanie.

Często zadawane pytania

Czy można używać @ObservedObject bez @StateObject w rodzicu?

Tak, jeśli obiekt jest tworzony i przechowywany poza SwiftUI — na przykład w AppDelegate lub singletonie. W tym przypadku @ObservedObject po prostu subskrybuje zmiany istniejącego obiektu. Jednak dla obiektów tworzonych wewnątrz hierarchii SwiftUI zawsze potrzebny jest @StateObject gdzieś wyżej.

Dlaczego @ObservedObject czasami nie aktualizuje View?

Najbardziej prawdopodobna przyczyna — właściwość jest zmieniana nie przez @Published lub zmienia się nie sam obiekt, a jego wewnętrzna struktura bez wywołania objectWillChange. Dla kolekcji używaj przypisania nowej kopii: array.append() nie wystarczy — trzeba przypisać całą tablicę na nowo przez array = array + [element].

Czy @ObservedObject wpływa na wydajność?

@ObservedObject sam w sobie nie tworzy znaczącego obciążenia. Problemy pojawiają się przy częstych zmianach właściwości @Published — każda zmiana wyzwala przerysowanie wszystkich obserwujących View. Do optymalizacji używaj EquatableView, zmniejszaj liczbę właściwości published i unikaj zbędnych aktualizacji.

Czym @ObservedObject różni się od @Binding?

@ObservedObject obserwuje całą klasę ObservableObject i przerysowuje View przy każdej zmianie jego właściwości published. @Binding tworzy dwukierunkowe połączenie z konkretną wartością (String, Int, Bool) i pozwala ją czytać i zapisywać. @Binding jest lżejszy i nie wymaga ObservableObject.

Czy można łączyć @ObservedObject z @Published w jednej klasie?

Tak, to standardowy wzorzec. @Published wewnątrz ObservableObject automatycznie integruje się z @ObservedObject. Każda właściwość @Published dodaje obserwatora do publishera objectWillChange. Przy zmianie dowolnej z nich wszystkie View z @ObservedObject dla tego obiektu są przerysowywane.

Podsumowanie

  • @ObservedObject — property wrapper do obserwacji ObservableObject utworzonego w innym miejscu hierarchii.
  • Nie posiada obiektu — w przeciwieństwie do @StateObject, @ObservedObject nie zarządza cyklem życia i nie tworzy obiektu.
  • Subskrypcja przez Combine — SwiftUI automatycznie subskrybuje publisher objectWillChange ObservableObject.
  • iOS 13+ — @ObservedObject jest dostępny od pierwszej wersji SwiftUI, co jest ważne dla projektów ze starszym wsparciem.
  • Przekazanie przez inicjalizator — obiekt jest jawnie przekazywany do podrzędnego View, co czyni zależności przejrzystymi.
  • Błąd własności — użycie @ObservedObject do tworzenia obiektu prowadzi do utraty danych przy odbudowie View.
  • Alternatywy — @EnvironmentObject do wstrzykiwania przez środowisko, @State/@Binding dla typów wartościowych.

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również