@ObservedObject è un property wrapper in SwiftUI che consente a una View di osservare i cambiamenti in un ObservableObject creato altrove nella gerarchia. A differenza di @StateObject, @ObservedObject non crea l’oggetto — si sottoscrive solo al suo publisher objectWillChange e ridisegna la View quando le proprietà pubblicate vengono aggiornate. Questo rende @ObservedObject la scelta corretta per le View figlie che ricevono dati da un genitore tramite un inizializzatore. Secondo un articolo di Paul Hudson — Hacking with Swift (2025), un’architettura tipica di un’app SwiftUI si costruisce così: la View radice usa @StateObject per creare un view model, e tutte le View figlie lo ricevono tramite @ObservedObject, garantendo un’unica fonte di verità senza duplicazione di dati.
Punti chiave
@ObservedObject è un property wrapper che sottoscrive una View ai cambiamenti ObservableObject. Quando un oggetto marcato con @ObservedObject modifica una qualsiasi delle sue proprietà dichiarate con @Published, SwiftUI ridisegna automaticamente la View. @ObservedObject non crea l’oggetto — stabilisce solo una connessione tra un’istanza ObservableObject esistente e la View che deve reagire ai suoi cambiamenti.
La differenza chiave tra @ObservedObject e @StateObject è la proprietà. @ObservedObject presuppone che l’oggetto sia creato e memorizzato più in alto nella gerarchia delle View. La View figlia riceve un riferimento a questo oggetto tramite l’inizializzatore e semplicemente lo osserva. Se la View figlia viene ricreata, riceve lo stesso riferimento dal genitore — i dati non vengono persi.
Secondo la Documentazione Apple Developer — SwiftUI (2025), @ObservedObject è disponibile a partire da iOS 13, rendendolo l’unica opzione per osservare ObservableObject in progetti che supportano versioni iOS precedenti. In iOS 14+, @StateObject è preferito per creare oggetti, ma @ObservedObject rimane rilevante per passare oggetti esistenti.
Il meccanismo di @ObservedObject si basa sul protocollo ObservableObject del framework Combine. Ogni classe conforme a ObservableObject ottiene automaticamente un publisher objectWillChange che invia un segnale prima di qualsiasi modifica a una proprietà @Published. SwiftUI si sottoscrive a questo publisher tramite @ObservedObject e, al ricevimento del segnale, marca la View come bisognosa di ridisegno.
class TaskViewModel: ObservableObject {
@Published var tasks: [Task] = []
@Published var isLoading = false
func loadTasks() async {
isLoading = true
// recupera dati
isLoading = false
}
}
struct TaskListView: View {
@ObservedObject var viewModel: TaskViewModel
var body: some View {
List(viewModel.tasks) { task in
Text(task.title)
}
.task { await viewModel.loadTasks() }
}
}
Quando la View genitore passa viewModel a TaskListView tramite l’inizializzatore, SwiftUI crea una connessione tra l’oggetto e la View. Quando l’array tasks o il flag isLoading cambiano, SwiftUI ridisegna TaskListView. L’oggetto stesso rimane invariato — viene memorizzato nella View genitore tramite @StateObject.
La differenza tra @ObservedObject e @StateObject è la differenza tra un osservatore e un proprietario. @StateObject crea l’oggetto e gestisce il suo ciclo di vita. @ObservedObject osserva solo un oggetto che è stato creato e memorizzato altrove. La scelta tra di essi è determinata dalla responsabilità della View verso i dati.
| Scenario | Raccomandazione | Motivo |
|---|---|---|
| La View crea dati | @StateObject | La View possiede l’oggetto ed è responsabile del suo ciclo di vita |
| La View riceve dati | @ObservedObject | La View osserva solo, l’oggetto vive nel genitore |
| Supporto iOS 13 | @ObservedObject | @StateObject non disponibile, usa @ObservedObject con gestione manuale |
| Componente riutilizzabile | @ObservedObject | Il componente non deve creare dati — li riceve esternamente |
La regola principale: se la View crea l’oggetto — @StateObject. Se la View riceve l’oggetto — @ObservedObject. Violare questa regola usando @ObservedObject per creare un oggetto porta alla perdita di dati quando la View viene ricostruita. Violarla usando @StateObject per ricevere un oggetto crea un’istanza duplicata indipendente dal genitore.
Uno scenario tipico di utilizzo di @ObservedObject è un elenco di attività in cui la View radice crea un view model e ogni cella dell’elenco lo riceve tramite @ObservedObject. Ogni cella può chiamare metodi del view model, e i cambiamenti si riflettono automaticamente sull’intero elenco poiché tutte le celle osservano lo stesso oggetto.
struct TaskRow: View {
@ObservedObject var viewModel: TaskViewModel
let task: Task
var body: some View {
HStack {
Text(task.title)
Spacer()
Button("Fatto") {
viewModel.completeTask(task)
}
}
}
}
struct TaskListContainer: View {
@StateObject var viewModel = TaskViewModel()
var body: some View {
List(viewModel.tasks) { task in
TaskRow(viewModel: viewModel, task: task)
}
}
}
In questo esempio, TaskListContainer crea viewModel tramite @StateObject, e ogni TaskRow lo riceve tramite @ObservedObject. Quando l’utente preme “Done” in qualsiasi riga, viewModel.completeTask modifica una proprietà pubblicata, e tutte le View che osservano questo oggetto si aggiornano automaticamente.
L’errore più comune è usare @ObservedObject per creare un oggetto all’interno di una View. Quando la View viene ricostruita (ad esempio, quando lo stato cambia), SwiftUI crea una nuova istanza ObservableObject, portando alla perdita di tutti i dati accumulati. Questo errore è particolarmente doloroso in NavigationStack, dove un utente potrebbe compilare un modulo e perdere i dati tornando indietro.
// ❌ Perdita dati: @ObservedObject non trattiene l’oggetto
struct FormView: View {
@ObservedObject var formVM = FormViewModel()
// Nuovo formVM creato ad ogni ricostruzione della View!
}
// ✅ Corretto: @StateObject trattiene l’oggetto
struct FormView: View {
@StateObject var formVM = FormViewModel()
// Oggetto creato una volta per durata della View
}
Se una View figlia dichiara lo stesso ObservableObject tramite @StateObject, crea una copia indipendente. I cambiamenti nell’oggetto genitore non saranno visibili nella figlia, e viceversa. Usa sempre @ObservedObject per le View figlie che ricevono l’oggetto esternamente.
In SwiftUI moderno esistono diverse alternative a @ObservedObject, ciascuna con i propri vantaggi. La scelta dipende dall’architettura dell’applicazione, dalla versione di iOS e dal caso d’uso specifico.
La scelta tra @ObservedObject e @EnvironmentObject è una questione di stile e architettura. @ObservedObject mostra esplicitamente le dipendenze della View tramite l’inizializzatore, rendendo il codice più prevedibile. @EnvironmentObject è comodo per gerarchie profonde ma nasconde le dipendenze, il che può complicare il debugging.
Domande frequenti
Sì, se l’oggetto è creato e memorizzato al di fuori di SwiftUI — ad esempio, in un AppDelegate o singleton. In questo caso, @ObservedObject si sottoscrive semplicemente ai cambiamenti di un oggetto esistente. Tuttavia, per oggetti creati all’interno della gerarchia SwiftUI, @StateObject è sempre necessario a qualche livello superiore.
La ragione più probabile è che la proprietà viene modificata non tramite @Published o che l’oggetto stesso non viene modificato ma la sua struttura interna muta senza chiamare objectWillChange. Per le collezioni, usa l’assegnazione di una nuova copia: array.append() non basta — devi riassegnare l’array stesso tramite array = array + [element].
@ObservedObject di per sé non crea un overhead significativo. I problemi sorgono con cambiamenti frequenti delle proprietà @Published — ogni cambiamento attiva un ridisegno di tutte le View osservatrici. Per ottimizzare, usa EquatableView, riduci il numero di proprietà pubblicate ed evita aggiornamenti non necessari.
@ObservedObject osserva un’intera classe ObservableObject e ridisegna la View ad ogni cambiamento delle sue proprietà pubblicate. @Binding crea una connessione bidirezionale con un valore specifico (String, Int, Bool) e consente di leggerlo e scriverlo. @Binding è più leggero e non richiede ObservableObject.
Sì, questo è il pattern standard. @Published all’interno di ObservableObject si integra automaticamente con @ObservedObject. Ogni proprietà @Published aggiunge un osservatore al publisher objectWillChange. Quando una di esse cambia, tutte le View con @ObservedObject per questo oggetto vengono ridisegnate.
Riepilogo
Svilupperemo 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