@ObservedObject: co to jest, jak działa i przykłady

Autor: IT Sectr Opublikowano: 2026-06-19 Czas czytania: 7 min

@ObservedObject to Property Wrapper w SwiftUI do obserwowania instancji ObservableObject przekazanej z zewnątrz. W przeciwieństwie do @StateObject, @ObservedObject nie tworzy obiektu – subskrybuje zmiany już istniejącego. Według Apple Developer Documentation (2025), @ObservedObject jest używane w widokach potomnych, które muszą śledzić dane należące do rodzica. @ObservedObject zapewnia reaktywne połączenie bez zarządzania cyklem życia obiektu.

Najważniejsze

  • @ObservedObject – Property Wrapper do obserwowania ObservableObject bez posiadania
  • Bez tworzenia – obiekt przekazywany z widoku rodzica lub środowiska
  • @Published – właściwości wewnątrz ObservableObject, których zmiany śledzi SwiftUI
  • Przerysowanie – przy zmianie właściwości @Published SwiftUI aktualizuje wszystkie subskrybujące widoki
  • Nie mylić z @StateObject – @ObservedObject nie gwarantuje pojedynczej instancji

Czym jest @ObservedObject w SwiftUI?

@ObservedObject to Property Wrapper, który subskrybuje widok na zmiany ObservableObject. ObservableObject to protokół z frameworka Combine, który wymaga implementacji publishera objectWillChange. Gdy dowolna właściwość oznaczona @Published zmienia się wewnątrz ObservableObject, publisher wysyła sygnał, a SwiftUI przerysowuje wszystkie widoki subskrybujące przez @ObservedObject.

Główną cechą @ObservedObject jest brak posiadania. Widok nie odpowiada za tworzenie ani niszczenie obiektu. Obiekt jest tworzony w widoku rodzica (przez @StateObject) lub wstrzykiwany przez @EnvironmentObject. Widok potomny tylko obserwuje zmiany i otrzymuje aktualizacje. Jeśli obiekt zostanie zastąpiony w rodzicu, @ObservedObject przełączy się na nową instancję.

@ObservedObject nadaje się do scenariuszy ze współdzieleniem danych: model użytkownika, wspólne ustawienia, stan połączenia z serwerem. Gdy wiele widoków na różnych poziomach hierarchii musi wyświetlać te same dane, @ObservedObject w każdym widoku tworzy niezależne, ale spójne subskrypcje jednego źródła.

@ObservedObject vs @StateObject: kluczowe różnice

Różnica między @ObservedObject a @StateObject to jeden z najczęstszych tematów pytań na rozmowach kwalifikacyjnych z SwiftUI. Podstawowa zasada: @StateObject tworzy i posiada obiekt, @ObservedObject obserwuje już istniejący. Naruszenie tej zasady prowadzi do nieoczekiwanej utraty danych lub podwójnej inicjalizacji.

Charakterystyka@StateObject@ObservedObject
Tworzenie obiektuTak, przy inicjalizacji widokuNie, otrzymuje gotowy
PosiadanieBieżący widokKomponent rodzica
Pojedyncza instancjaTak, przez cały cykl życiaNie, może być zastąpiona
Ponowne tworzenie przy renderzeNie, zachowywanaZależy od rodzica
Gdzie używaćGłówny widok-właścicielWidoki potomne

@StateObject gwarantuje, że obiekt jest tworzony raz i przetrwa wielokrotne inicjalizacje struktury widoku. @ObservedObject otrzymuje obiekt z zewnątrz i jest ponownie tworzony przy każdej inicjalizacji struktury rodzica. Jeśli rodzic używa @StateObject dla obiektu, widoki potomne mogą bezpiecznie stosować @ObservedObject – obiekt będzie jedyny w całej hierarchii.

Jak @ObservedObject śledzi zmiany

Mechanizm śledzenia @ObservedObject opiera się na Combine i protokole ObservableObject. Przy inicjalizacji SwiftUI wywołuje publisher objectWillChange – obiekt musi wysłać sygnał przed zmianą właściwości @Published. Combine przekazuje sygnał do grafu zależności SwiftUI, który oznacza wszystkie zależne widoki jako wymagające aktualizacji. Dzieje się to synchronicznie przed zmianą wartości.

swift
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")
        }
    }
}

W listingu WeatherService to ObservableObject z dwiema właściwościami @Published. WeatherView deklaruje @ObservedObject var weather: WeatherService, otrzymując instancję od rodzica. Gdy temperature się zmienia, objectWillChange uruchamia się przed ustawieniem nowej wartości, SwiftUI przerysowuje WeatherView i wyświetlana jest aktualna temperatura. Subskrypcja jest automatycznie zarządzana przez SwiftUI – programista nie musi wywoływać sink ani dispose.

Wzorce użycia @ObservedObject

Pierwszy wzorzec – przekazywanie modelu przez inicjalizator. Rodzic tworzy ObservableObject przez @StateObject i przekazuje go widokom potomnym jako @ObservedObject. To standardowe hierarchiczne przekazywanie danych, w którym główny widok zarządza cyklem życia modelu, a wszystkie zagnieżdżone komponenty subskrybują zmiany.

Drugi wzorzec – EnvironmentObject, globalna wersja @ObservedObject przez SwiftUI Environment. Obiekt jest wstrzykiwany na poziomie sceny lub głównego widoku i automatycznie dostępny wszystkim komponentom potomnym bez jawnego przekazywania przez inicjalizatory. Wewnątrz widoku potomnego @EnvironmentObject działa podobnie do @ObservedObject, ale pobiera obiekt ze środowiska.

Trzeci wzorzec – kompozycja wielu ObservableObject. W złożonych aplikacjach widok może obserwować wiele obiektów: @ObservedObject var user: UserService, @ObservedObject var network: NetworkMonitor. Rozdziela to odpowiedzialność między serwisy i zachowuje testowalność każdego komponentu.

swift
struct DashboardView: View {
    @ObservedObject var user: UserViewModel
    @ObservedObject var network: NetworkMonitor

    var body: some View {
        VStack {
            Text("Witaj, \\(user.name)")
            HStack {
                Circle()
                    .fill(network.isConnected ? Color.green : Color.red)
                    .frame(width: 10, height: 10)
            }
        }
    }
}

DashboardView obserwuje UserViewModel i NetworkMonitor. Każdy obiekt odpowiada za swój obszar danych i niezależnie powiadamia widok o zmianach. Jeśli sieć się rozłączy, NetworkMonitor zmienia isConnected, a SwiftUI przerysowuje DashboardView, aktualizując kolor wskaźnika. Kompozycja ObservableObject to preferowany sposób organizacji danych w aplikacjach SwiftUI.

@Published: połączenie ObservableObject i SwiftUI

@Published to Property Wrapper z Combine, który automatycznie dodaje wydawcę do właściwości wewnątrz ObservableObject. Gdy właściwość @Published się zmienia, Combine generuje zdarzenie przez publisher objectWillChange. SwiftUI subskrybuje tego publishera przy użyciu @ObservedObject lub @StateObject i przerysowuje widok przy każdej nowej wartości.

@Published obsługuje wszystkie typy, w tym opcjonalne, kolekcje i struktury niestandardowe. Jednak dla kolekcji (tablice, słowniki) SwiftUI śledzi tylko zamianę referencji, a nie zmianę zawartości. Aby wykryć dodanie lub usunięcie elementu, należy ponownie przypisać całą kolekcję albo użyć ObservableObject z manualnym objectWillChange.send().

Ważny szczegół: @Published może znajdować się tylko wewnątrz klasy implementującej ObservableObject. Użycie @Published poza ObservableObject spowoduje błąd kompilacji. @Published nie można również stosować do właściwości leniwej inicjalizacji (lazy var) ani właściwości obliczanych (computed property).

Typowe błędy z @ObservedObject

Najbardziej krytyczny błąd – użycie @ObservedObject do tworzenia obiektu. Jeśli napiszesz @ObservedObject var model = UserViewModel() w widoku rodzica, przy każdym renderze będzie tworzona nowa instancja UserViewModel. Dane zostaną utracone, a subskrypcje @Published odtworzone. Zawsze używaj @StateObject do tworzenia i @ObservedObject tylko do otrzymywania gotowego obiektu.

Drugi błąd – zmiana właściwości @Published poza głównym wątkiem. ObservableObject używa Combine, który wymaga wysyłania zmian na głównym wątku (main actor). Jeśli zmienisz @Published w kolejce tła, SwiftUI może przerysować widok w nieodpowiednim momencie, powodując race conditions. Używaj DispatchQueue.main.async lub @MainActor do aktualizacji.

Trzeci problem – cykliczne aktualizacje. Jeśli zmiana @Published wywołuje efekty uboczne, które ponownie zmieniają @Published, powstaje nieskończona pętla przerysowań. Rozwiązanie: używaj flag ochronnych (isUpdating) lub rozdzielaj logikę na różne ObservableObject z wyraźnymi granicami odpowiedzialności.

Często zadawane pytania

Czy @ObservedObject może być opcjonalny?

Tak, SwiftUI obsługuje @ObservedObject var model: UserViewModel?. Jednak widok nie będzie subskrybował zmian, dopóki obiekt jest nil. Po przypisaniu wartości subskrypcja aktywuje się automatycznie.

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

@ObservedObject otrzymuje obiekt przez inicjalizator, @EnvironmentObject – przez SwiftUI Environment. @EnvironmentObject nie wymaga jawnego przekazywania przez konstruktory, ale obiekt musi być wstrzyknięty na górnym poziomie hierarchii.

Jak ręcznie powiadomić SwiftUI o zmianie ObservableObject?

Wywołaj objectWillChange.send() przed zmianą właściwości. Jest to przydatne, jeśli @Published nie pasuje (na przykład dla właściwości obliczanych lub operacji na kolekcjach, gdzie trzeba zgłosić zmianę przed mutacją).

Dlaczego @ObservedObject nie przerysowuje widoku przy zmianie wewnątrz tablicy?

@ObservedObject i @Published śledzą zamianę referencji, a nie mutację zawartości kolekcji. Do przerysowania należy ponownie przypisać tablicę: items.append(newItem) → items = items lub użyć objectWillChange.send() przed mutacją.

Czy można użyć @ObservedObject w strukturze nieimplementującej View?

Nie, @ObservedObject to Property Wrapper SwiftUI dostępny tylko wewnątrz typów implementujących protokół View. Dla zwykłych struktur używaj Combine bezpośrednio z ObservableObjectPublisher.

Podsumowanie

  • @ObservedObject – Property Wrapper do obserwowania ObservableObject bez posiadania
  • @StateObject – tworzy obiekt, @ObservedObject – obserwuje istniejący
  • @Published – automatyczny publisher dla właściwości ObservableObject
  • Subskrypcja – SwiftUI automatycznie zarządza subskrypcją Combine przy użyciu @ObservedObject
  • Kompozycja – widok może obserwować wiele ObservableObject jednocześnie
  • Main actor – właściwości @Published należy zmieniać tylko na głównym wątku
  • EnvironmentObject – alternatywa dla @ObservedObject do niejawnego przekazywania przez środowisko

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ż