@Published è un property wrapper del framework Combine che pubblica automaticamente le modifiche di una proprietà di classe conforme al protocollo ObservableObject. Quando il valore di una proprietà contrassegnata con @Published cambia, SwiftUI riceve un segnale attraverso objectWillChange e ridisegna tutte le view sottoscritte a quell'oggetto. Secondo la documentazione Apple Combine Framework (2025), @Published genera un Publisher che può essere ulteriormente trasformato attraverso gli operatori Combine: map, filter, debounce e altri. Ciò rende @Published un ponte chiave tra i dati e l'interfaccia utente nell'architettura MVVM.
Punti chiave
objectWillChange, che attiva il ridisegno delle view sottoscritte$property — è possibile sottoscriversi, combinare e trasformare il flusso@Published è un property wrapper definito nel modulo Combine che aggiunge la possibilità di notificare automaticamente gli abbonati delle modifiche a una proprietà di classe. Può essere utilizzato solo all'interno di una classe (non in una struct) e solo su proprietà di una classe conforme al protocollo ObservableObject.
Quando il valore di una proprietà @Published cambia, Combine genera un evento attraverso un publisher integrato accessibile tramite il prefisso dollaro: $propertyName. Questo publisher è un ObservableObjectPublisher, che appartiene all'ObservableObject stesso. SwiftUI vi si sottoscrive automaticamente quando una view utilizza @ObservedObject o @StateObject, e ridisegna la view ogni volta che qualsiasi proprietà @Published all'interno dell'oggetto cambia.
Secondo il libro di Matt Neuburg “IOS 18 Programming Fundamentals with Swift” (2025), @Published è un wrapper conveniente sul pattern willSet, che chiama automaticamente objectWillChange.send(). In effetti, il compilatore espande @Published in una proprietà calcolata con un osservatore willSet, fornendo un overhead runtime pari a zero rispetto all'implementazione manuale.
Utilizza @Published per tutte le proprietà ObservableObject le cui modifiche devono essere riflesse nell'interfaccia. Per le proprietà che non influenzano l'UI, le normali proprietà memorizzate senza @Published riducono i ridisegni non necessari.
@Published genera due elementi chiave al momento della compilazione. Il primo è una proprietà memorizzata con un osservatore willSet che chiama objectWillChange.send() prima di scrivere il nuovo valore. Il secondo è la proiezione $propertyName, che restituisce un Published.Publisher che può essere utilizzato direttamente nelle pipeline Combine.
Considera la classe Settings con tre proprietà: due @Published e una normale:
class Settings: ObservableObject {
@Published var username: String = "Guest"
@Published var isDarkMode = false
var lastLogin: Date = Date() // without @Published
}
Quando username o isDarkMode cambia, SwiftUI ridisegnerà tutte le view sottoscritte all'istanza Settings. La modifica di lastLogin non attiverà un ridisegno. Se è necessario notificare manualmente gli abbonati di una modifica a una proprietà normale, è possibile chiamare objectWillChange.send() nell'osservatore willSet.
Un dettaglio importante: @Published pubblica le modifiche solo quando una proprietà viene assegnata direttamente. Se la proprietà è di tipo riferimento (classe) e il suo stato interno cambia senza sostituire il riferimento, @Published non lo rileverà. In tali casi, è necessario l'invio manuale di eventi o il passaggio a un tipo valore (struct).
@Published è strettamente integrato con Combine — ogni proprietà @Published fornisce automaticamente un publisher accessibile tramite la proiezione $propertyName. Ciò consente di utilizzare gli operatori Combine per filtrare, trasformare, combinare ed elaborare i valori in modo differito.
Uno scenario tipico è la ricerca con debounce. Un campo di input è legato alla proprietà @Published searchText, ma la richiesta al server deve essere inviata solo dopo una pausa di 300 ms. Combine con $searchText.debounce risolve questo problema in una riga:
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) { }
}
Secondo l'articolo di John Sundell (Swift by Sundell, 2024), combinare @Published con Combine è un modello standard per le pipeline reattive nelle applicazioni SwiftUI: validazione, debounce, throttle, combineLatest, merge con altri publisher. @Published funge da ponte tra il codice UI imperativo e Combine reattivo.
Con il rilascio di iOS 17, Apple ha introdotto la macro @Observable, che offre un approccio alternativo alla reattività senza ObservableObject e @Published. @Observable tiene traccia automaticamente dell'accesso alle proprietà a livello di lettura anziché di scrittura, fornendo ridisegni più precisi — solo la view che legge una specifica proprietà modificata viene aggiornata.
Tuttavia, ciò non significa che @Published sia obsoleto. @Published rimane necessario quando è richiesta l'integrazione con le pipeline Combine — la proiezione $propertyName fornisce un publisher che @Observable non ha. Inoltre, per la compatibilità con iOS 16 e versioni precedenti, @Published+ObservableObject è l'unica opzione. Secondo la sessione Apple WWDC 2023 “Discover Observation in SwiftUI,” Apple raccomanda @Observable per i nuovi progetti, ma mantiene esplicitamente il supporto per @Published per il codice esistente e gli scenari Combine.
In pratica, molti progetti utilizzano un approccio ibrido: i nuovi modelli di dati usano @Observable, mentre gli ObservableObject esistenti con @Published rimangono senza refactoring. @Published è inoltre indispensabile quando è richiesto un controllo preciso sulla pubblicazione — ad esempio, ritardare la notifica fino al completamento di un aggiornamento batch di più proprietà.
Il primo errore è l'utilizzo di @Published in una struct. Il compilatore genererà un errore: “Property wrapper cannot be applied to a computed property” o “‘@Published’ is only available on members of a class.” @Published richiede semantica di riferimento perché ObservableObjectPublisher è una classe che deve essere unica per ogni istanza.
Il secondo errore è mutare il contenuto di una proprietà di riferimento senza sostituire il riferimento. Se una proprietà @Published è di tipo array [String] e si chiama array.append("nuovo"), @Published non rileverà la modifica perché il riferimento all'array non è cambiato. Soluzione: assegnare un nuovo valore alla proprietà array = array + ["nuovo"] o utilizzare objectWillChange.send() manualmente.
Il terzo errore è un numero eccessivo di proprietà @Published. Ogni proprietà @Published attiva un ridisegno di tutte le view sottoscritte all'ObservableObject, non solo di quelle che leggono quella proprietà. Secondo Point-Free (2025), dividere un grande ObservableObject in più piccoli con @StateObject e @EnvironmentObject riduce i ridisegni non necessari e migliora le prestazioni.
Il primo esempio è un ViewModel di modulo di registrazione con validazione. Le proprietà @Published email e password attivano la visualizzazione degli errori di validazione attraverso una pipeline 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)
}
}
Il secondo esempio è la pubblicazione manuale per una collezione di elementi di riferimento. Invece di sostituire l'intero array a ogni modifica all'interno di un elemento, viene utilizzato 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
}
}
Il terzo esempio è Assign a una proprietà @Published tramite Combine. Utilizzando la nuova sintassi Swift 5.9, è possibile assegnare direttamente tramite la proiezione assign(to: &$property) senza wrapper Optional. Questo è il modo più breve per collegare un publisher a una proprietà @Published senza creare un abbonamento.
Domande frequenti
No, @Published può essere utilizzato solo all'interno di una classe conforme a ObservableObject. Nelle struct, utilizza @State per lo stato locale o @Bindable con la macro @Observable in iOS 17+. Tentare di utilizzare @Published in una struct causerà un errore di compilazione.
Approccio corretto: assegna il nuovo valore completamente (array = array + ["nuovo"]). @Published tiene traccia della sostituzione del riferimento, non della mutazione del contenuto. Per le collezioni di tipi riferimento, utilizza la chiamata manuale objectWillChange.send() dopo aver mutato lo stato interno degli elementi.
@State è progettato per lo stato locale all'interno di una singola view e funziona solo con tipi valore. @Published è per le proprietà ObservableObject che possono essere lette da più view tramite @ObservedObject o @EnvironmentObject. @State è più semplice, @Published è più potente grazie all'integrazione con Combine.
Solo quelle le cui modifiche devono aggiornare l'UI. Le proprietà per calcoli interni, cache o flag temporanei non necessitano di @Published — ciò riduce i ridisegni non necessari. Usa @Published come segnale che “questa proprietà è importante per l'interfaccia.”
SwiftUI si integra con Core Data attraverso @FetchRequest e @ObservedObject per NSManagedObject. ManagedObject è già conforme a ObservableObject, quindi @Published non è necessario — NSManagedObject notifica le modifiche autonomamente. @Published viene utilizzato nel livello ViewModel tra Core Data e UI per la trasformazione dei dati.
Riepilogo
objectWillChange.send(), generando un publisher tramite la proiezione $propertyassign(to: &$property) in Swift 5.9 consente di abbonare un publisher direttamente a una proprietà @PublishedSvilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche