@Published — property wrapper из фреймворка Combine, который автоматически публикует изменения свойства класса, conforming к протоколу ObservableObject. Когда значение свойства, помеченного @Published, изменяется, SwiftUI получает сигнал через objectWillChange и перерисовывает все view, подписанные на этот объект. По данным Apple Combine Framework Documentation (2025), @Published генерирует Publisher, который можно дополнительно трансформировать через операторы Combine: map, filter, debounce и другие. Это делает @Published ключевым мостом между данными и пользовательским интерфейсом в архитектуре MVVM.
Главное
objectWillChange, что триггерит перерисовку подписанных view$property — можно подписываться, комбинировать и трансформировать поток@Published — это property wrapper, определённый в модуле Combine, который добавляет к свойству класса возможность автоматически уведомлять подписчиков об изменениях. Он может применяться только внутри класса (не в структуре) и только к свойствам класса, conforming к протоколу 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, что даёт нулевой оверхед на runtime по сравнению с ручной реализацией.
Используйте @Published для всех свойств ObservableObject, изменения которых должны отражаться в интерфейсе. Для свойств, не влияющих на UI, обычные stored properties без @Published снижают количество лишних перерисовок.
@Published генерирует два ключевых элемента при компиляции. Первый — хранимое свойство с willSet-наблюдателем, который вызывает objectWillChange.send() перед записью нового значения. Второй — проекция $propertyName, возвращающая Published.Publisher, который можно использовать напрямую в Combine-пайплайнах.
Рассмотрим класс Settings с тремя свойствами: два @Published и одно обычное:
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-свойство автоматически предоставляет publisher, доступный через проекцию $propertyName. Это позволяет применять операторы Combine для фильтрации, трансформации, объединения и отложенной обработки значений.
Типичный сценарий — поиск с debounce. Поле ввода привязано к @Published свойству searchText, но запрос к серверу должен отправляться только после паузы в 300 мс. Combine с $searchText.debounce решает это одной строкой:
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 acts как мост между императивным UI кодом и реактивным Combine.
С выходом 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 в структуре. Компилятор выдаст ошибку: «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:
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():
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 может применяться только внутри класса, conforming к ObservableObject. В структурах используйте @State для локального состояния или @Bindable с макросом @Observable в iOS 17+. Попытка применить @Published в структуре вызовет ошибку компиляции.
Правильно: присваивайте новое значение целиком (array = array + ["new"]). @Published отслеживает замену ссылки, а не мутацию содержимого. Для коллекций ссылочных типов используйте ручной вызов objectWillChange.send() после мутации внутреннего состояния элементов.
@State предназначен для локального состояния внутри одной view и работает только с value types. @Published — для свойств ObservableObject, которые могут читаться множеством view через @ObservedObject или @EnvironmentObject. @State проще, @Published мощнее благодаря интеграции с Combine.
Только для тех, чьи изменения должны обновлять UI. Свойства для внутренних расчётов, кэши или временные флаги не требуют @Published — это снижает количество лишних перерисовок. Используйте @Published как сигнал «это свойство важно для интерфейса».
SwiftUI интегрируется с Core Data через @FetchRequest и @ObservedObject для NSManagedObject. ManagedObject уже conforms к ObservableObject, поэтому @Published не нужен — NSManagedObject сам уведомляет об изменениях. @Published используется в ViewModel-слое между Core Data и UI для трансформации данных.
Итоги
objectWillChange.send(), генерируя publisher через проекцию $propertyassign(to: &$property) в Swift 5.9 позволяет подписать publisher напрямую на @Published свойствоМы разработаем мобильное приложение под ключ
IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.
Читайте также