@Published es un property wrapper del framework Combine que publica automáticamente los cambios de una propiedad de clase que conforma al protocolo ObservableObject. Cuando el valor de una propiedad marcada con @Published cambia, SwiftUI recibe una señal a través de objectWillChange y redibuja todas las vistas suscritas a ese objeto. Según la documentación de Apple Combine Framework (2025), @Published genera un Publisher que se puede transformar adicionalmente mediante operadores de Combine: map, filter, debounce y otros. Esto convierte a @Published en un puente clave entre los datos y la interfaz de usuario en la arquitectura MVVM.
Puntos clave
objectWillChange, lo que desencadena el redibujado de las vistas suscritas$property — permite suscribirse, combinar y transformar el flujo@Published es un property wrapper definido en el módulo Combine que añade la capacidad de notificar automáticamente a los suscriptores sobre los cambios de una propiedad de clase. Solo se puede usar dentro de una clase (no en una estructura) y únicamente en propiedades de una clase que conforme al protocolo ObservableObject.
Cuando el valor de una propiedad @Published cambia, Combine genera un evento a través de un publisher incorporado accesible mediante el prefijo de dólar: $propertyName. Este publisher es un ObservableObjectPublisher, que pertenece al propio ObservableObject. SwiftUI se suscribe automáticamente a él cuando una vista usa @ObservedObject o @StateObject, y redibuja la vista cada vez que cualquier propiedad @Published dentro del objeto cambia.
Según el libro de Matt Neuburg “IOS 18 Programming Fundamentals with Swift” (2025), @Published es un envoltorio conveniente sobre el patrón willSet, que llama automáticamente a objectWillChange.send(). De hecho, el compilador expande @Published en una propiedad computada con un observer willSet, lo que proporciona una sobrecarga de runtime nula en comparación con la implementación manual.
Use @Published para todas las propiedades de ObservableObject cuyos cambios deban reflejarse en la interfaz. Para propiedades que no afectan a la UI, las propiedades almacenadas normales sin @Published reducen los redibujados innecesarios.
@Published genera dos elementos clave en tiempo de compilación. El primero es una propiedad almacenada con un observer willSet que llama a objectWillChange.send() antes de escribir el nuevo valor. El segundo es la proyección $propertyName, que devuelve un Published.Publisher que se puede usar directamente en pipelines de Combine.
Considere la clase Settings con tres propiedades: dos @Published y una normal:
class Settings: ObservableObject {
@Published var username: String = "Guest"
@Published var isDarkMode = false
var lastLogin: Date = Date() // without @Published
}
Cuando username o isDarkMode cambian, SwiftUI redibujará todas las vistas suscritas a la instancia de Settings. El cambio de lastLogin no desencadenará un redibujado. Si necesita notificar manualmente a los suscriptores sobre un cambio en una propiedad normal, puede llamar a objectWillChange.send() en el observer willSet.
Un detalle importante: @Published solo publica cambios cuando se asigna directamente una propiedad. Si la propiedad es de tipo referencia (clase) y su estado interno cambia sin reemplazar la referencia, @Published no lo detectará. En tales casos, se requiere el envío manual de eventos o el cambio a un tipo valor (estructura).
@Published está estrechamente integrado con Combine — cada propiedad @Published proporciona automáticamente un publisher accesible a través de la proyección $propertyName. Esto permite usar operadores de Combine para filtrar, transformar, combinar y procesar valores de forma diferida.
Un escenario típico es la búsqueda con debounce. Un campo de entrada está vinculado a la propiedad @Published searchText, pero la solicitud al servidor solo debe enviarse después de una pausa de 300 ms. Combine con $searchText.debounce resuelve esto en una línea:
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) { }
}
Según el artículo de John Sundell (Swift by Sundell, 2024), combinar @Published con Combine es un patrón estándar para pipelines reactivos en aplicaciones SwiftUI: validación, debounce, throttle, combineLatest, merge con otros publishers. @Published actúa como un puente entre el código UI imperativo y Combine reactivo.
Con el lanzamiento de iOS 17, Apple presentó el macro @Observable, que ofrece un enfoque alternativo a la reactividad sin ObservableObject ni @Published. @Observable rastrea automáticamente el acceso a las propiedades a nivel de lectura en lugar de escritura, lo que proporciona redibujados más precisos — solo se actualiza la vista que lee una propiedad modificada específica.
Sin embargo, esto no significa que @Published esté obsoleto. @Published sigue siendo necesario cuando se necesita integración con pipelines de Combine — la proyección $propertyName proporciona un publisher que @Observable no tiene. Además, para la compatibilidad con iOS 16 y versiones anteriores, @Published+ObservableObject es la única opción. Según la sesión de Apple WWDC 2023 “Discover Observation in SwiftUI,” Apple recomienda @Observable para proyectos nuevos, pero mantiene explícitamente el soporte de @Published para código existente y escenarios de Combine.
En la práctica, muchos proyectos usan un enfoque híbrido: los nuevos modelos de datos usan @Observable, mientras que los ObservableObject existentes con @Published permanecen sin refactorizar. @Published también es indispensable cuando se requiere un control preciso sobre la publicación — por ejemplo, retrasar la notificación hasta que se complete una actualización por lotes de varias propiedades.
El primer error es usar @Published en una estructura. El compilador generará un error: “Property wrapper cannot be applied to a computed property” o “‘@Published’ is only available on members of a class.” @Published requiere semántica de referencia porque ObservableObjectPublisher es una clase que debe ser única para cada instancia.
El segundo error es mutar el contenido de una propiedad de referencia sin reemplazar la referencia. Si una propiedad @Published es de tipo array [String] y usted llama a array.append("new"), @Published no detectará el cambio porque la referencia al array no ha cambiado. Solución: asigne un nuevo valor a la propiedad array = array + ["new"] o use objectWillChange.send() manualmente.
El tercer error es una cantidad excesiva de propiedades @Published. Cada propiedad @Published desencadena un redibujado de todas las vistas suscritas al ObservableObject, no solo de aquellas que leen esa propiedad. Según Point-Free (2025), dividir un ObservableObject grande en varios más pequeños con @StateObject y @EnvironmentObject reduce los redibujados innecesarios y mejora el rendimiento.
El primer ejemplo es un ViewModel de formulario de registro con validación. Las propiedades @Published email y password desencadenan la visualización de errores de validación a través de un pipeline de Combine:
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)
}
}
El segundo ejemplo es la publicación manual para una colección de elementos de referencia. En lugar de reemplazar todo el array en cada cambio dentro de un elemento, se usa 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
}
}
El tercer ejemplo es Assign a una propiedad @Published a través de Combine. Usando la nueva sintaxis de Swift 5.9, puede asignar directamente a través de la proyección assign(to: &$property) sin envoltorio Optional. Esta es la forma más corta de conectar un publisher a una propiedad @Published sin crear una suscripción.
Preguntas frecuentes
No, @Published solo se puede usar dentro de una clase que conforme a ObservableObject. En estructuras, use @State para el estado local o @Bindable con el macro @Observable en iOS 17+. Intentar usar @Published en una estructura provocará un error de compilación.
Enfoque correcto: asigne el nuevo valor por completo (array = array + ["new"]). @Published rastrea el reemplazo de la referencia, no la mutación del contenido. Para colecciones de tipos de referencia, use el llamado manual objectWillChange.send() después de mutar el estado interno de los elementos.
@State está diseñado para el estado local dentro de una sola vista y solo funciona con tipos valor. @Published es para propiedades de ObservableObject que pueden ser leídas por múltiples vistas a través de @ObservedObject o @EnvironmentObject. @State es más simple, @Published es más potente gracias a la integración con Combine.
Solo aquellas cuyos cambios deban actualizar la UI. Las propiedades para cálculos internos, cachés o banderas temporales no necesitan @Published — esto reduce los redibujados innecesarios. Use @Published como una señal de que “esta propiedad es importante para la interfaz.”
SwiftUI se integra con Core Data a través de @FetchRequest y @ObservedObject para NSManagedObject. ManagedObject ya conforma a ObservableObject, por lo que @Published no es necesario — NSManagedObject notifica los cambios por sí mismo. @Published se usa en la capa ViewModel entre Core Data y la UI para la transformación de datos.
Resumen
objectWillChange.send(), generando un publisher a través de la proyección $propertyassign(to: &$property) en Swift 5.9 permite suscribir un publisher directamente a una propiedad @PublishedDesarrollaremos una aplicación móvil llave en mano
IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.
Lea también