@Published: що це, принцип роботи та застосування

Автор: IT Sectr Опубліковано: 2026-06-19 Час читання: 8 хв

@Published — це property wrapper із фреймворку Combine, який автоматично публікує зміни властивості класу, що відповідає протоколу ObservableObject. Коли значення властивості, позначеної @Published, змінюється, SwiftUI отримує сигнал через objectWillChange і перемальовує всі view, підписані на цей об'єкт. Згідно з документацією Apple Combine Framework (2025), @Published генерує Publisher, який можна додатково трансформувати через оператори Combine: map, filter, debounce та інші. Це робить @Published ключовим мостом між даними та інтерфейсом користувача в архітектурі MVVM.

Головне

  • @Published — property wrapper для автоматичної публікації змін властивостей ObservableObject у SwiftUI та Combine
  • Механізм: при зміні значення викликається objectWillChange, що тригерить перемальовування підписаних view
  • Publisher доступний через проекцію $property — можна підписуватися, комбінувати та трансформувати потік
  • ObservedObject і StateObject автоматично підписуються на властивості @Published — ручне підписання не потрібне
  • iOS 17+ макрос @Observable пропонує альтернативу, але @Published залишається стандартом для Combine-пайплайнів

Що таке @Published?

@Published — це property wrapper, визначений у модулі Combine, який додає можливість автоматично сповіщати підписників про зміни властивості класу. Він може застосовуватися лише всередині класу (не в структурі) і лише до властивостей класу, що відповідає протоколу ObservableObject.

При зміні значення властивості @Published Combine генерує подію через вбудований publisher, доступний через префікс долара: $propertyName. Цей publisher — ObservableObjectPublisher, який належить самому ObservableObject. SwiftUI автоматично підписується на нього, коли view використовує @ObservedObject або @StateObject, і перемальовує view при будь-якій зміні будь-якої властивості @Published всередині об'єкта.

Згідно з книгою Метта Нойбурга «IOS 18 Programming Fundamentals with Swift» (2025), @Published — це зручна обгортка над патерном willSet, яка автоматично викликає objectWillChange.send(). Фактично компілятор розгортає @Published у computed property з willSet observer, що дає нульовий overhead на runtime порівняно з ручною реалізацією.

Використовуйте @Published для всіх властивостей ObservableObject, зміни яких повинні відображатися в інтерфейсі. Для властивостей, що не впливають на UI, звичайні stored properties без @Published зменшують кількість зайвих перемальовувань.

Як працює @Published

@Published генерує два ключові елементи при компіляції. Перший — властивість, що зберігається, з willSet-спостерігачем, який викликає objectWillChange.send() перед записом нового значення. Другий — проекція $propertyName, яка повертає Published.Publisher, що можна використовувати безпосередньо в Combine-пайплайнах.

Розглянемо клас Settings із трьома властивостями: дві @Published і одна звичайна:

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

При зміні username або isDarkMode SwiftUI перемалює всі view, підписані на екземпляр Settings. Зміна lastLogin не викличе перемальовування. Якщо потрібно вручну сповістити підписників про зміну звичайної властивості, можна викликати objectWillChange.send() у willSet-спостерігачі.

Важлива деталь: @Published публікує зміни лише при прямому записі у властивість. Якщо властивість є посилальним типом (клас) і змінюється його внутрішній стан без заміни посилання, @Published цього не помітить. У таких випадках потрібне ручне надсилання події або заміна на value type (структуру).

@Published і Combine

@Published тісно інтегрований із Combine — кожна властивість @Published автоматично надає publisher, доступний через проекцію $propertyName. Це дозволяє застосовувати оператори Combine для фільтрації, трансформації, об'єднання та відкладеної обробки значень.

Типовий сценарій — пошук із debounce. Поле введення прив'язане до властивості @Published searchText, але запит до сервера має надсилатися лише після паузи в 300 мс. Combine із $searchText.debounce вирішує це одним рядком:

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

Згідно зі статтею Джона Сандлса (Swift by Sundell, 2024), комбінування @Published із Combine — стандартний патерн для реактивних пайплайнів у SwiftUI-додатках: validation, debounce, throttle, combineLatest, merge з іншими publishers. @Published виступає як міст між імперативним UI кодом і реактивним Combine.

@Published vs макрос @Observable

З виходом iOS 17 Apple представила макрос @Observable, який пропонує альтернативний підхід до реактивності без ObservableObject і @Published. @Observable автоматично відстежує доступ до властивостей на рівні читання, а не запису, що дає більш точні перемальовування — оновлюється лише той view, який читає конкретну змінену властивість.

Однак це не означає, що @Published застарів. @Published залишається необхідним, коли потрібна інтеграція з Combine-пайплайнами — проекція $propertyName дає publisher, якого немає у @Observable. Крім того, для зворотної сумісності з iOS 16 та нижче @Published+ObservableObject — єдиний варіант. Згідно з сесією Apple WWDC 2023 «Discover Observation in SwiftUI», Apple рекомендує @Observable для нових проєктів, але явно зберігає підтримку @Published для існуючого коду та Combine-сценаріїв.

На практиці багато проєктів використовують гібридний підхід: нові моделі даних пишуться на @Observable, а існуючі ObservableObject із @Published залишаються без рефакторингу. @Published також незамінний, коли потрібен тонкий контроль над публікацією — наприклад, відкласти сповіщення до завершення пакетного оновлення кількох властивостей.

Типові помилки з @Published

Перша помилка — застосування @Published у структурі. Компілятор видасть помилку: «Property wrapper cannot be applied to a computed property» або «‘@Published’ is only available on members of a class.» @Published вимагає посилальної семантики, оскільки ObservableObjectPublisher — це клас, який має бути унікальним для кожного екземпляра.

Друга помилка — мутація вмісту посилальної властивості без заміни посилання. Якщо властивість @Published має тип масиву [String] і ви викликаєте array.append("new"), @Published не вловить зміну, тому що посилання на масив не змінилося. Рішення: присвоїти властивості нове значення array = array + ["new"] або використати objectWillChange.send() вручну.

Третя помилка — надмірна кількість властивостей @Published. Кожна властивість @Published викликає перемальовування всіх view, підписаних на ObservableObject, а не лише тих, що читають цю властивість. Згідно з Point-Free (2025), розділення одного великого ObservableObject на кілька маленьких із @StateObject і @EnvironmentObject зменшує кількість зайвих перемальовувань і покращує продуктивність.

Приклади коду

Перший приклад — ViewModel форми реєстрації з валідацією. Властивості @Published email і password тригерять відображення помилок валідації через 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)
    }
}

Другий приклад — ручна публікація для колекції посилальних елементів. Замість заміни всього масиву при кожній зміні всередині елемента використовується 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()  // manual notification
    }
}

Третій приклад — Assign до властивості @Published через Combine. Використовуючи новий синтаксис Swift 5.9, можна безпосередньо присвоювати через проекцію assign(to: &$property) без Optional-обгортки. Це найкоротший шлях зв'язати publisher із властивістю @Published без створення підписки.

Поширені запитання

Чи можна використовувати @Published у структурі?

Ні, @Published може застосовуватися лише всередині класу, що відповідає ObservableObject. У структурах використовуйте @State для локального стану або @Bindable з макросом @Observable в iOS 17+. Спроба застосувати @Published у структурі викличе помилку компіляції.

Як @Published працює з масивами та словниками?

Правильно: присвоюйте нове значення цілком (array = array + ["new"]). @Published відстежує заміну посилання, а не мутацію вмісту. Для колекцій посилальних типів використовуйте ручний виклик objectWillChange.send() після мутації внутрішнього стану елементів.

Чим @Published відрізняється від @State?

@State призначений для локального стану всередині одного view і працює лише з value types. @Published — для властивостей ObservableObject, які можуть читатися багатьма view через @ObservedObject або @EnvironmentObject. @State простіший, @Published потужніший завдяки інтеграції з Combine.

Чи потрібен @Published для кожної властивості ObservableObject?

Лише для тих, чиї зміни повинні оновлювати UI. Властивості для внутрішніх розрахунків, кешу або тимчасових прапорців не потребують @Published — це зменшує кількість зайвих перемальовувань. Використовуйте @Published як сигнал «ця властивість важлива для інтерфейсу».

Як @Published працює з Core Data?

SwiftUI інтегрується з Core Data через @FetchRequest і @ObservedObject для NSManagedObject. ManagedObject вже відповідає ObservableObject, тому @Published не потрібен — NSManagedObject сам сповіщає про зміни. @Published використовується в ViewModel-шарі між Core Data та UI для трансформації даних.

Підсумки

  • @Published — property wrapper із Combine, який автоматично публікує зміни властивостей ObservableObject для SwiftUI та Combine-пайплайнів
  • Механізм: willSet observer викликає objectWillChange.send(), генеруючи publisher через проекцію $property
  • Combine: @Published дає publisher для debounce, map, combineLatest та інших операторів — це міст між UI та реактивними пайплайнами
  • @Observable (iOS 17+) — альтернатива для нових проєктів, але @Published залишається стандартом для Combine та зворотної сумісності
  • Помилки: @Published не працює в структурах, не відстежує мутацію посилальних типів, надмірна кількість @Published збільшує перемальовування
  • Найкраща практика: позначайте @Published лише властивості, що впливають на UI, розділяйте великі ObservableObject на кілька маленьких
  • Assign: assign(to: &$property) у Swift 5.9 дозволяє підписати publisher безпосередньо на властивість @Published

Ми розробимо мобільний застосунок під ключ

IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

Читайте також