@Published: what it is, how it works, and application

Author: IT Sectr Published: 2026-06-19 Reading time: 8 min

@Published is a property wrapper from the Combine framework that automatically publishes changes to a class property conforming to the ObservableObject protocol. When the value of a property marked with @Published changes, SwiftUI receives a signal through objectWillChange and redraws all views subscribed to that object. According to Apple Combine Framework Documentation (2025), @Published generates a Publisher that can be further transformed using Combine operators: map, filter, debounce, and others. This makes @Published a key bridge between data and the user interface in the MVVM architecture.

Key Takeaways

  • @Published — a property wrapper for automatically publishing changes to ObservableObject properties in SwiftUI and Combine
  • Mechanism: when the value changes, objectWillChange is called, triggering a redraw of subscribed views
  • Publisher is accessible via the $property projection — you can subscribe, combine, and transform the stream
  • ObservedObject and StateObject automatically subscribe to @Published properties — manual subscription is not required
  • iOS 17+ the @Observable macro offers an alternative, but @Published remains the standard for Combine pipelines

What is @Published?

@Published is a property wrapper defined in the Combine module that adds the ability to automatically notify subscribers of changes to a class property. It can only be used inside a class (not a struct) and only on properties of a class conforming to the ObservableObject protocol.

When a @Published property value changes, Combine generates an event through a built-in publisher accessible via the dollar prefix: $propertyName. This publisher is an ObservableObjectPublisher, which belongs to the ObservableObject itself. SwiftUI automatically subscribes to it when a view uses @ObservedObject or @StateObject, and redraws the view whenever any @Published property within the object changes.

According to Matt Neuburg’s book “IOS 18 Programming Fundamentals with Swift” (2025), @Published is a convenient wrapper over the willSet pattern, automatically calling objectWillChange.send(). In effect, the compiler expands @Published into a computed property with a willSet observer, providing zero runtime overhead compared to manual implementation.

Use @Published for all ObservableObject properties whose changes should be reflected in the interface. For properties that do not affect the UI, regular stored properties without @Published reduce unnecessary redraws.

How @Published Works

@Published generates two key elements at compile time. The first is a stored property with a willSet observer that calls objectWillChange.send() before writing the new value. The second is the $propertyName projection, which returns a Published.Publisher that can be used directly in Combine pipelines.

Consider the Settings class with three properties: two @Published and one regular:

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

When username or isDarkMode changes, SwiftUI will redraw all views subscribed to the Settings instance. Changing lastLogin will not trigger a redraw. If you need to manually notify subscribers of a change to a regular property, you can call objectWillChange.send() in the willSet observer.

An important detail: @Published only publishes changes when a property is directly assigned. If the property is a reference type (class) and its internal state changes without replacing the reference, @Published will not detect it. In such cases, manual event sending or switching to a value type (struct) is required.

@Published and Combine

@Published is tightly integrated with Combine — each @Published property automatically provides a publisher accessible via the $propertyName projection. This allows using Combine operators for filtering, transforming, combining, and deferred value processing.

A typical scenario is search with debounce. An input field is bound to the @Published property searchText, but the server request should only be sent after a 300 ms pause. Combine with $searchText.debounce solves this in one line:

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) { }
}

According to John Sundell’s article (Swift by Sundell, 2024), combining @Published with Combine is a standard pattern for reactive pipelines in SwiftUI applications: validation, debounce, throttle, combineLatest, merge with other publishers. @Published acts as a bridge between imperative UI code and reactive Combine.

@Published vs @Observable Macro

With the release of iOS 17, Apple introduced the @Observable macro, which offers an alternative approach to reactivity without ObservableObject and @Published. @Observable automatically tracks property access at the read level rather than write level, providing more precise redraws — only the view that reads a specific changed property gets updated.

However, this does not mean @Published is deprecated. @Published remains necessary when Combine pipeline integration is needed — the $propertyName projection provides a publisher that @Observable does not have. Additionally, for backward compatibility with iOS 16 and below, @Published+ObservableObject is the only option. According to Apple WWDC 2023 session “Discover Observation in SwiftUI,” Apple recommends @Observable for new projects but explicitly maintains support for @Published for existing code and Combine scenarios.

In practice, many projects use a hybrid approach: new data models use @Observable, while existing ObservableObject with @Published remain without refactoring. @Published is also indispensable when fine-grained control over publication is required — for example, delaying notification until a batch update of multiple properties is complete.

Common Mistakes with @Published

The first mistake is using @Published in a struct. The compiler will throw an error: “Property wrapper cannot be applied to a computed property” or “‘@Published’ is only available on members of a class.” @Published requires reference semantics because ObservableObjectPublisher is a class that must be unique for each instance.

The second mistake is mutating the contents of a reference property without replacing the reference. If a @Published property is of array type [String] and you call array.append("new"), @Published will not detect the change because the reference to the array has not changed. Solution: assign a new value to the property array = array + ["new"] or use objectWillChange.send() manually.

The third mistake is an excessive number of @Published properties. Each @Published property triggers a redraw of all views subscribed to the ObservableObject, not just those that read that property. According to Point-Free (2025), splitting one large ObservableObject into several smaller ones with @StateObject and @EnvironmentObject reduces unnecessary redraws and improves performance.

Code Examples

The first example is a registration form ViewModel with validation. The @Published properties email and password trigger validation error display through a Combine pipeline:

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

The second example is manual publication for a collection of reference elements. Instead of replacing the entire array on every change within an element, objectWillChange.send() is used:

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()  // manual notification
    }
}

The third example is Assign to a @Published property through Combine. Using the new Swift 5.9 syntax, you can directly assign via the assign(to: &$property) projection without an Optional wrapper. This is the shortest way to connect a publisher to a @Published property without creating a subscription.

Frequently Asked Questions

Can @Published be used in a struct?

No, @Published can only be used inside a class conforming to ObservableObject. In structs, use @State for local state or @Bindable with the @Observable macro in iOS 17+. Attempting to use @Published in a struct will cause a compilation error.

How does @Published work with arrays and dictionaries?

Correct approach: assign the new value entirely (array = array + ["new"]). @Published tracks reference replacement, not content mutation. For collections of reference types, use manual objectWillChange.send() after mutating the internal state of elements.

How is @Published different from @State?

@State is designed for local state within a single view and only works with value types. @Published is for ObservableObject properties that can be read by multiple views via @ObservedObject or @EnvironmentObject. @State is simpler, @Published is more powerful thanks to Combine integration.

Does every ObservableObject property need @Published?

Only those whose changes should update the UI. Properties for internal calculations, caches, or temporary flags do not need @Published — this reduces unnecessary redraws. Use @Published as a signal that “this property matters for the interface.”

How does @Published work with Core Data?

SwiftUI integrates with Core Data through @FetchRequest and @ObservedObject for NSManagedObject. ManagedObject already conforms to ObservableObject, so @Published is not needed — NSManagedObject notifies changes on its own. @Published is used in the ViewModel layer between Core Data and UI for data transformation.

Summary

  • @Published — a property wrapper from Combine that automatically publishes ObservableObject property changes for SwiftUI and Combine pipelines
  • Mechanism: a willSet observer calls objectWillChange.send(), generating a publisher via the $property projection
  • Combine: @Published provides a publisher for debounce, map, combineLatest, and other operators — a bridge between UI and reactive pipelines
  • @Observable (iOS 17+) — an alternative for new projects, but @Published remains the standard for Combine and backward compatibility
  • Mistakes: @Published does not work in structs, does not track reference type mutation, excessive @Published properties increase redraws
  • Best practice: mark only UI-affecting properties with @Published, split large ObservableObjects into smaller ones
  • Assign: assign(to: &$property) in Swift 5.9 allows subscribing a publisher directly to a @Published property

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also