@StateObject: cos'è, creazione e gestione di ObservableObject

Autore: IT Sectr Pubblicato: 2026-06-26 Tempo di lettura: 9 min

@StateObject è un property wrapper in SwiftUI che crea e possiede un'istanza di ObservableObject per l'intero ciclo di vita di una View. Quando una View appare per la prima volta sullo schermo, @StateObject inizializza l'oggetto e lo conserva fino a quando la View non viene rimossa dalla memoria. Questo garantisce che i dati non vengano reimpostati durante la ricostruzione dell'interfaccia — ad esempio, quando si cambia tema o si aggiorna la View padre. Secondo la Documentazione per Sviluppatori Apple (2025), @StateObject dovrebbe essere utilizzato come fonte primaria di verità (source of truth) per ObservableObject nella gerarchia SwiftUI, mentre le Views figlie ricevono l'oggetto già creato tramite @ObservedObject o @EnvironmentObject.

Punti Chiave

  • @StateObject è un property wrapper per creare e possedere un ObservableObject all'interno di una View.
  • Creazione singola — l'oggetto viene inizializzato una volta durante la vita della View e non viene ricreato durante le ricostruzioni.
  • Fonte di verità — @StateObject è la fonte di verità nella gerarchia, a differenza di @ObservedObject.
  • Ciclo di vita — l'oggetto vive finché la View esiste in memoria e viene distrutto insieme ad essa.
  • Inizializzazione — @StateObject richiede un valore iniziale alla creazione, solitamente tramite init con parametri.

Cos'è @StateObject in SwiftUI

@StateObject è un property wrapper introdotto in iOS 14 che permette a una View di creare e possedere un'istanza di una classe conforme al protocollo ObservableObject. A differenza di @State, che lavora con tipi valore (struct), @StateObject è progettato per tipi riferimento — classi che possono notificare SwiftUI sui cambiamenti delle loro proprietà.

Quando una View usa @StateObject var viewModel: MyViewModel, SwiftUI crea automaticamente un'istanza di MyViewModel quando la View appare per la prima volta e la conserva in un archivio speciale del framework. Ad ogni aggiornamento della View (ad esempio, quando lo stato padre cambia), SwiftUI non ricrea l'oggetto — utilizza l'istanza esistente fino a quando la View non viene rimossa dalla gerarchia.

Secondo Apple WWDC Session 10137 (2024), @StateObject risolve il problema di perdita di dati che esisteva in iOS 13 quando le Views venivano ricostruite, costringendo gli sviluppatori a creare ObservableObject nella View padre e passarlo tramite l'inizializzatore. Questo portava a duplicazione di codice e al rischio di ricreare accidentalmente l'oggetto.

swift
import SwiftUI

class CounterViewModel: ObservableObject {
    @Published var count: Int = 0
    
    func increment() {
        count += 1
    }
}

struct CounterView: View {
    @StateObject var viewModel = CounterViewModel()
    
    var body: some View {
        VStack {
            Text("Count: \(viewModel.count)")
            Button("Increment", action: viewModel.increment)
        }
    }
}

Come funziona @StateObject

Il meccanismo di @StateObject si basa sull'integrazione di SwiftUI con il framework Combine. Quando un ObservableObject contrassegna le sue proprietà con l'attributo @Published, SwiftUI si iscrive automaticamente ai cambiamenti tramite il publisher integrato nel protocollo ObservableObject. Quando una proprietà pubblicata cambia, l'oggetto invia un segnale tramite il publisher objectWillChange, che attiva un ridisegno di tutte le Views che osservano questo oggetto.

SwiftUI conserva l'istanza di ObservableObject in un archivio speciale legato a una specifica istanza di View. Questo archivio viene creato una volta durante il primo rendering ed esiste fino a quando la View non viene distrutta. Ecco perché @StateObject garantisce la stabilità del riferimento — SwiftUI gestisce la memoria automaticamente, senza dipendere dall'inizializzatore della View.

Secondo objc.io — Thinking in SwiftUI (2025), l'implementazione interna di @StateObject utilizza un meccanismo simile a @State ma per tipi riferimento: SwiftUI crea un involucro (boxing) attorno all'oggetto e gestisce il suo ciclo di vita tramite il proprio allocatore, ottimizzato per frequenti ricostruzioni della gerarchia delle Views.

Ciclo di vita di @StateObject

  • Creazione — quando la View appare per la prima volta sullo schermo, SwiftUI chiama l'inizializzatore dell'oggetto e conserva il riferimento.
  • Ricostruzione — quando la View padre viene aggiornata, l'oggetto non viene ricreato; viene utilizzata l'istanza esistente.
  • Distruzione — quando la View lascia lo schermo e viene rimossa dalla gerarchia, SwiftUI chiama il deinit dell'oggetto.

@StateObject vs @ObservedObject: differenze chiave

La differenza principale tra @StateObject e @ObservedObject sta in chi possiede l'oggetto. @StateObject crea e conserva l'oggetto — ne è il proprietario. @ObservedObject osserva solo l'oggetto che è stato creato altrove e passato tramite inizializzatore o proprietà.

Caratteristica@StateObject@ObservedObject
ProprietàCrea e possiede l'oggettoOsserva solo
InizializzazioneDentro la View tramite init/defaultEsterna, passata tramite parametro
Ciclo di vitaLegato al ciclo di vita della ViewNon controllato dalla View
RicreazioneNon viene ricreato all'aggiornamentoPuò essere sostituito esternamente
Versione iOSiOS 14+iOS 13+

La regola è semplice: se la View crea l'ObservableObject — usa @StateObject. Se la View riceve solo un oggetto già creato dal padre — usa @ObservedObject. Violare questa regola porta o alla perdita di dati (se si usa @ObservedObject per la proprietà) o alla creazione eccessiva di oggetti (se si usa @StateObject per l'osservazione).

Quando usare @StateObject

@StateObject dovrebbe essere usato nelle Views che sono la fonte di verità per un insieme specifico di dati. Gli scenari tipici includono schermate con il proprio view model, schermate radice di stack di navigazione e presentazioni modali che gestiscono il proprio stato.

  • Schermata con view model — ogni schermata che gestisce i propri dati e logica dovrebbe creare il proprio view model tramite @StateObject.
  • View radice — in una gerarchia NavigationStack o TabView, l'elemento radice crea i dati e gli elementi figli li ricevono tramite @ObservedObject.
  • Finestre modali — .sheet e .fullScreenCover spesso richiedono un proprio @StateObject per gestire un modulo o un processo.
  • Lista modificabile — ogni riga di lista che contiene un modulo di modifica dovrebbe avere il proprio @StateObject.
swift
struct ProfileView: View {
    @StateObject var viewModel = ProfileViewModel()
    
    var body: some View {
        NavigationStack {
            Form {
                TextField("Name", text: $viewModel.name)
                TextField("Email", text: $viewModel.email)
                Button("Save") {
                    viewModel.saveProfile()
                }
            }
            .navigationTitle("Profile")
        }
    }
}

Inizializzare @StateObject con parametri

Inizializzare @StateObject con parametri richiede una sintassi speciale, poiché SwiftUI gestisce la creazione dell'oggetto autonomamente. Non puoi semplicemente passare parametri all'inizializzatore — devi utilizzare una closure di escape o un metodo factory separato.

Secondo Swift by Sundell (2024), l'approccio più pulito è utilizzare un metodo factory o una closure che SwiftUI chiamerà quando l'oggetto viene creato per la prima volta. Un approccio alternativo è inizializzare l'ObservableObject nella View padre e passarlo tramite @StateObject utilizzando l'inizializzatore standard.

swift
class UserViewModel: ObservableObject {
    @Published var user: User
    
    init(user: User) {
        self.user = user
    }
}

struct UserDetailView: View {
    @StateObject var viewModel: UserViewModel
    
    init(user: User) {
        _viewModel = StateObject(wrappedValue: UserViewModel(user: user))
    }
    
    var body: some View {
        Text(viewModel.user.name)
    }
}

È importante ricordare che l'inizializzatore di View con @StateObject dovrebbe usare un underscore prima del nome della proprietà (_viewModel) per accedere al property wrapper stesso, non al suo valore. Questo è un pattern Swift standard per lavorare con i property wrapper negli inizializzatori.

Errori comuni con @StateObject

L'errore più comune è usare @ObservedObject invece di @StateObject per una View che dovrebbe possedere l'oggetto. In questo caso, ogni volta che il padre viene ricostruito, l'oggetto verrà ricreato, portando alla perdita di tutti i dati accumulati. Questo errore è particolarmente insidioso in gerarchie complesse con NavigationStack o TabView.

  • Perdita di dati durante la navigazione — se una schermata figlia usa @ObservedObject per il proprio view model, i dati verranno reimpostati quando si torna indietro e si riapre.
  • Fuga di memoria — creare @StateObject in una View padre che non viene mai rimossa può portare all'accumulo di oggetti se ogni schermata figlia crea anch'essa @StateObject senza controllo.
  • Duplicazione di oggetti — passare un singolo ObservableObject a più @StateObject in diverse Views crea diverse istanze indipendenti che non si sincronizzano tra loro.

Per evitare questi problemi, segui una regola semplice: un @StateObject per fonte di verità. Se i dati devono essere condivisi tra più schermate — crea @StateObject una volta nella View radice e passalo tramite @ObservedObject o @EnvironmentObject agli elementi figli.

swift
// ❌ Wrong: @ObservedObject for owning an object
struct BadView: View {
    @ObservedObject var vm = ViewModel() // will be recreated on each update!
}

// ✅ Correct: @StateObject for owning
struct GoodView: View {
    @StateObject var vm = ViewModel() // created once for View lifetime
}

Domande Frequenti

Qual è la differenza tra @StateObject e @State?

@State lavora con tipi valore (struct, stringhe, numeri) e conserva il valore direttamente nell'archivio SwiftUI. @StateObject lavora con tipi riferimento — classi conformi a ObservableObject. @State è adatto per stati locali semplici, @StateObject per oggetti complessi con logica e proprietà pubblicate.

Posso usare @StateObject in iOS 13?

No, @StateObject è disponibile solo da iOS 14 in poi. Per iOS 13, usa @ObservedObject e crea l'ObservableObject nella View padre tramite @State con gestione manuale del ciclo di vita. Un'alternativa è usare @State con un struct invece di una classe per dati che non richiedono semantica di riferimento.

Cosa succede se uso @StateObject in una View figlia dove l'oggetto viene passato dal padre?

La View figlia creerà la propria copia dell'ObservableObject, completamente indipendente da quella del padre. I cambiamenti in una non influenzeranno l'altra. Questo è quasi sempre un errore: usa @ObservedObject per ricevere un oggetto dal padre e @StateObject solo per creare un nuovo oggetto all'interno della View.

Quando viene distrutto un oggetto creato tramite @StateObject?

L'oggetto viene distrutto quando la View che lo ha creato viene completamente rimossa dalla gerarchia SwiftUI. Per una schermata in NavigationStack, ciò accade quando si fa pop dallo stack di navigazione. Per una finestra modale — quando viene chiusa. Per TabView — quando si cambia scheda, se la View non è memorizzata nella cache.

Come passare parametri a @StateObject durante l'inizializzazione?

Usa un init personalizzato con accesso al property wrapper tramite underscore: _viewModel = StateObject(wrappedValue: MyViewModel(param: value)). Questo pattern permette di passare qualsiasi parametro all'ObservableObject, mantenendo al contempo la garanzia di creazione singola dell'oggetto durante la vita della View.

Riepilogo

  • @StateObject — un property wrapper per creare e possedere un ObservableObject all'interno di una View, disponibile da iOS 14.
  • Garanzia di creazione singola — l'oggetto viene inizializzato una volta e non viene ricreato quando la View viene ricostruita.
  • Fonte di verità — @StateObject è la fonte di verità, mentre @ObservedObject è solo un osservatore.
  • Ciclo di vita — l'oggetto vive finché la View esiste nella gerarchia SwiftUI e viene distrutto quando la abbandona.
  • Inizializzazione con parametri — richiede accesso al property wrapper tramite _viewModel e StateObject(wrappedValue:).
  • Errore di proprietà — usare @ObservedObject per creare un oggetto porta alla perdita di dati durante la ricostruzione.
  • Un oggetto — un @StateObject — per dati condivisi, crea @StateObject nella View radice e passalo ai figli tramite @ObservedObject.

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.

Discuti il progetto

Leggi anche