@Published: co to jest, zasada działania i zastosowanie

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

@Published — to property wrapper z frameworka Combine, który automatycznie publikuje zmiany właściwości klasy zgodnej z protokołem ObservableObject. Gdy wartość właściwości oznaczonej @Published zmienia się, SwiftUI otrzymuje sygnał przez objectWillChange i przerysowuje wszystkie widoki subskrybujące ten obiekt. Według Apple Combine Framework Documentation (2025), @Published generuje Publisher, który można dodatkowo transformować za pomocą operatorów Combine: map, filter, debounce i innych. To czyni @Published kluczowym mostem między danymi a interfejsem użytkownika w architekturze MVVM.

Najważniejsze

  • @Published — property wrapper do automatycznej publikacji zmian właściwości ObservableObject w SwiftUI i Combine
  • Mechanizm: przy zmianie wartości wywoływane jest objectWillChange, co wyzwala przerysowanie subskrybujących widoków
  • Publisher jest dostępny przez projekcję $property — można subskrybować, łączyć i transformować strumień
  • ObservedObject i StateObject automatycznie subskrybują właściwości @Published — ręczna subskrypcja nie jest wymagana
  • iOS 17+ makro @Observable oferuje alternatywę, ale @Published pozostaje standardem dla pipeline’ów Combine

Co to jest @Published?

@Published — to property wrapper zdefiniowany w module Combine, który dodaje do właściwości klasy możliwość automatycznego powiadamiania subskrybentów o zmianach. Może być stosowany tylko wewnątrz klasy (nie w strukturze) i tylko do właściwości klasy zgodnej z protokołem ObservableObject.

Przy zmianie wartości właściwości @Published, Combine generuje zdarzenie przez wbudowany publisher, dostępny przez prefiks dolara: $propertyName. Ten publisher to ObservableObjectPublisher, który należy do samego ObservableObject. SwiftUI automatycznie subskrybuje go, gdy widok używa @ObservedObject lub @StateObject, i przerysowuje widok przy każdej zmianie dowolnej właściwości @Published wewnątrz obiektu.

Według książki Matta Neuburga „IOS 18 Programming Fundamentals with Swift” (2025), @Published to wygodne opakowanie wzorca willSet, automatycznie wywołujące objectWillChange.send(). Faktycznie kompilator rozwija @Published we właściwość obliczaną z obserwatorem willSet, co daje zerowy narzut w czasie działania w porównaniu z ręczną implementacją.

Używaj @Published dla wszystkich właściwości ObservableObject, których zmiany mają być odzwierciedlone w interfejsie. Dla właściwości niewpływających na UI zwykłe stored properties bez @Published zmniejszają liczbę niepotrzebnych przerysowań.

Jak działa @Published

@Published generuje dwa kluczowe elementy podczas kompilacji. Pierwszy — przechowywana właściwość z obserwatorem willSet, który wywołuje objectWillChange.send() przed zapisaniem nowej wartości. Drugi — projekcja $propertyName, zwracająca Published.Publisher, który można użyć bezpośrednio w pipeline’ach Combine.

Rozważmy klasę Settings z trzema właściwościami: dwiema @Published i jedną zwykłą:

swift
class Settings: ObservableObject {
    @Published var username: String = "Guest"
    @Published var isDarkMode = false
    var lastLogin: Date = Date()  // bez @Published
}

Przy zmianie username lub isDarkMode SwiftUI przerysuje wszystkie widoki subskrybujące instancję Settings. Zmiana lastLogin nie wywoła przerysowania. Jeśli potrzebujesz ręcznie powiadomić subskrybentów o zmianie zwykłej właściwości, możesz wywołać objectWillChange.send() w obserwatorze willSet.

Ważny szczegół: @Published publikuje zmiany tylko przy bezpośrednim przypisaniu do właściwości. Jeśli właściwość jest typu referencyjnego (klasa) i zmienia się jej stan wewnętrzny bez zastąpienia referencji, @Published tego nie wychwyci. W takich przypadkach potrzebne jest ręczne wysłanie zdarzenia lub zastąpienie typem wartościowym (strukturą).

@Published i Combine

@Published jest ściśle zintegrowany z Combine — każda właściwość @Published automatycznie udostępnia publishera dostępnego przez projekcję $propertyName. Umożliwia to stosowanie operatorów Combine do filtrowania, transformacji, łączenia i opóźniania wartości.

Typowy scenariusz — wyszukiwanie z debounce. Pole wejściowe jest powiązane z właściwością @Published searchText, ale zapytanie do serwera powinno być wysyłane dopiero po pauzie 300 ms. Combine z $searchText.debounce rozwiązuje to w jednej linii:

swift
class SearchViewModel: ObservableObject {
    @Published var searchText = ""
    @Published var results: [String] = []
    private var cancellables = Set<AnyCancellable>()

    init() {
        setupSearchSubscription()
    }

    private func setupSearchSubscription() {
        $searchText
            .debounce(for: .milliseconds(300), scheduler: RunLoop.main)
            .removeDuplicates()
            .sink { [weak self] text in
                self?.performSearch(text)
            }
            .store(in: &cancellables)
    }

    private func performSearch(_ text: String) { }
}

Według artykułu Johna Sundella (Swift by Sundell, 2024), łączenie @Published z Combine to standardowy wzorzec dla reaktywnych pipeline’ów w aplikacjach SwiftUI: validation, debounce, throttle, combineLatest, merge z innymi publisherami. @Published działa jako most między imperatywnym kodem UI a reaktywnym Combine.

@Published vs makro @Observable

Wraz z wydaniem iOS 17 Apple przedstawiła makro @Observable, które oferuje alternatywne podejście do reaktywności bez ObservableObject i @Published. @Observable automatycznie śledzi dostęp do właściwości na poziomie odczytu, a nie zapisu, co daje bardziej precyzyjne przerysowania — aktualizowany jest tylko ten widok, który odczytuje konkretną zmienioną właściwość.

Nie oznacza to jednak, że @Published jest przestarzały. @Published pozostaje niezbędny, gdy potrzebna jest integracja z pipeline’ami Combine — projekcja $propertyName daje publishera, którego nie ma w @Observable. Ponadto dla wstecznej zgodności z iOS 16 i starszymi @Published+ObservableObject to jedyna opcja. Według Apple WWDC 2023 sesji „Discover Observation in SwiftUI”, Apple zaleca @Observable dla nowych projektów, ale wyraźnie utrzymuje wsparcie @Published dla istniejącego kodu i scenariuszy Combine.

W praktyce wiele projektów stosuje podejście hybrydowe: nowe modele danych są pisane z @Observable, a istniejące ObservableObject z @Published pozostają bez refaktoryzacji. @Published jest również niezastąpiony, gdy wymagana jest precyzyjna kontrola nad publikacją — na przykład opóźnienie powiadomienia do zakończenia zbiorczej aktualizacji kilku właściwości.

Typowe błędy z @Published

Pierwszy błąd — stosowanie @Published w strukturze. Kompilator zgłosi błąd: „Property wrapper cannot be applied to a computed property” lub „'@Published' is only available on members of a class”. @Published wymaga semantyki referencyjnej, ponieważ ObservableObjectPublisher to klasa, która musi być unikalna dla każdej instancji.

Drugi błąd — mutacja zawartości właściwości referencyjnej bez zastąpienia referencji. Jeśli właściwość @Published ma typ tablicy [String] i wywołujesz array.append("new"), @Published nie wychwyci zmiany, ponieważ referencja do tablicy się nie zmieniła. Rozwiązanie: przypisz właściwości nową wartość array = array + ["new"] lub użyj objectWillChange.send() ręcznie.

Trzeci błąd — nadmierna liczba właściwości @Published. Każda właściwość @Published wywołuje przerysowanie wszystkich widoków subskrybujących ObservableObject, a nie tylko tych, które odczytują tę właściwość. Według Point-Free (2025), podział jednego dużego ObservableObject na kilka małych z @StateObject i @EnvironmentObject zmniejsza liczbę niepotrzebnych przerysowań i poprawia wydajność.

Przykłady kodu

Pierwszy przykład — ViewModel formularza rejestracji z walidacją. Właściwości @Published email i password wyzwalają wyświetlanie błędów walidacji przez pipeline Combine:

swift
class RegistrationViewModel: ObservableObject {
    @Published var email = ""
    @Published var password = ""
    @Published var emailError: String?
    @Published var isFormValid = false
    private var cancellables = Set<AnyCancellable>()

    init() {
        $email
            .map { $0.contains("@") ? nil : "Invalid email" }
            .assign(to: &$emailError)
            .store(in: &cancellables)

        $email.combineLatest($password)
            .map { !$0.isEmpty && !$1.isEmpty }
            .assign(to: &$isFormValid)
            .store(in: &cancellables)
    }
}

Drugi przykład — ręczna publikacja dla kolekcji elementów referencyjnych. Zamiast zastępować całą tablicę przy każdej zmianie wewnątrz elementu używane jest objectWillChange.send():

swift
class TodoItem {
    var title: String
    var isDone = false
    init(title: String) { self.title = title }
}

class TodoListViewModel: ObservableObject {
    @Published var items: [TodoItem] = []

    func toggle(item: TodoItem) {
        item.isDone.toggle()
        self.objectWillChange.send()  // ręczne powiadomienie
    }
}

Trzeci przykład — Assign do właściwości @Published przez Combine. Używając nowej składni Swift 5.9, można bezpośrednio przypisywać przez projekcję assign(to: &$property) bez opakowania Optional. To najkrótsza droga do powiązania publishera z właściwością @Published bez tworzenia subskrypcji.

Często zadawane pytania

Czy można użyć @Published w strukturze?

Nie, @Published może być stosowany tylko wewnątrz klasy zgodnej z ObservableObject. W strukturach używaj @State dla lokalnego stanu lub @Bindable z makrem @Observable w iOS 17+. Próba zastosowania @Published w strukturze spowoduje błąd kompilacji.

Jak @Published działa z tablicami i słownikami?

Poprawnie: przypisuj nową wartość w całości (array = array + ["new"]). @Published śledzi zastąpienie referencji, a nie mutację zawartości. Dla kolekcji typów referencyjnych używaj ręcznego wywołania objectWillChange.send() po mutacji stanu wewnętrznego elementów.

Czym różni się @Published od @State?

@State jest przeznaczony dla lokalnego stanu w obrębie jednego widoku i działa tylko z typami wartościowymi. @Published — dla właściwości ObservableObject, które mogą być odczytywane przez wiele widoków przez @ObservedObject lub @EnvironmentObject. @State jest prostszy, @Published potężniejszy dzięki integracji z Combine.

Czy @Published jest potrzebny dla każdej właściwości ObservableObject?

Tylko dla tych, których zmiany mają aktualizować UI. Właściwości do obliczeń wewnętrznych, pamięci podręcznej lub tymczasowe flagi nie wymagają @Published — to zmniejsza liczbę niepotrzebnych przerysowań. Używaj @Published jako sygnału „ta właściwość jest ważna dla interfejsu”.

Jak @Published działa z Core Data?

SwiftUI integruje się z Core Data przez @FetchRequest i @ObservedObject dla NSManagedObject. ManagedObject jest już zgodny z ObservableObject, więc @Published nie jest potrzebny — NSManagedObject sam powiadamia o zmianach. @Published jest używany w warstwie ViewModel między Core Data a UI do transformacji danych.

Podsumowanie

  • @Published — property wrapper z Combine, automatycznie publikujący zmiany właściwości ObservableObject dla SwiftUI i pipeline’ów Combine
  • Mechanizm: observer willSet wywołuje objectWillChange.send(), generując publisher przez projekcję $property
  • Combine: @Published daje publisher dla debounce, map, combineLatest i innych operatorów — to most między UI a reaktywnymi pipeline’ami
  • @Observable (iOS 17+) — alternatywa dla nowych projektów, ale @Published pozostaje standardem dla Combine i wstecznej zgodności
  • Błędy: @Published nie działa w strukturach, nie śledzi mutacji typów referencyjnych, nadmierna liczba @Publisher zwiększa przerysowania
  • Najlepsza praktyka: oznaczaj @Published tylko właściwości wpływające na UI, dziel duże ObservableObject na kilka małych
  • Assign: assign(to: &$property) w Swift 5.9 umożliwia subskrypcję publishera bezpośrednio do właściwości @Published

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ż