@StateObject: ce este, crearea și gestionarea ObservableObject

Autor: IT Sectr Publicat: 2026-06-26 Timp de citire: 9 min

@StateObject este un property wrapper în SwiftUI care creează și deține o instanță ObservableObject pe tot parcursul ciclului de viață al View. Când View apare pentru prima dată pe ecran, @StateObject inițializează obiectul și îl păstrează până când View este eliminat din memorie. Acest lucru garantează că datele nu se resetează la reconstruirea interfeței — de exemplu, la schimbarea temei sau actualizarea View-ului părinte. Conform Apple Developer Documentation (2025), @StateObject ar trebui folosit ca sursă principală de adevăr (source of truth) pentru ObservableObject în ierarhia SwiftUI, în timp ce View-urile copil primesc obiectul deja creat prin @ObservedObject sau @EnvironmentObject.

Principalele puncte

  • @StateObject — property wrapper pentru crearea și deținerea ObservableObject în cadrul View.
  • O singură creare — obiectul este inițializat o dată pe durata de viață a View și nu este recreat la reconstruiri.
  • Source of truth — @StateObject este sursa de adevăr în ierarhie, spre deosebire de @ObservedObject.
  • Ciclul de viață — obiectul trăiește cât timp View există în memorie și este distrus odată cu acesta.
  • Inițializare — @StateObject necesită o valoare inițială la creare, de obicei prin init cu parametri.

Ce este @StateObject în SwiftUI

@StateObject este un property wrapper introdus în iOS 14 care permite unui View să creeze și să dețină o instanță a unei clase conforme cu protocolul ObservableObject. Spre deosebire de @State, care lucrează cu tipuri valoare (structuri), @StateObject este destinat tipurilor referință — clase care pot notifica SwiftUI despre modificările proprietăților lor.

Când View folosește @StateObject var viewModel: MyViewModel, SwiftUI creează automat instanța MyViewModel la prima afișare a View și o stochează într-un depozit special al framework-ului. La fiecare actualizare a View (de exemplu, la modificarea stării părinte), SwiftUI nu recrează obiectul — folosește instanța existentă până când View este eliminat din ierarhie.

Conform Apple WWDC Session 10137 (2024), @StateObject rezolvă problema pierderii de date la reconstruirea View care exista în iOS 13, când dezvoltatorii trebuiau să creeze ObservableObject în View-ul părinte și să îl transmită prin inițializator. Aceasta ducea la duplicarea codului și riscul de recreere accidentală a obiectului.

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("Număr: \(viewModel.count)")
            Button("Incrementează", action: viewModel.increment)
        }
    }
}

Cum funcționează @StateObject

Mecanismul @StateObject se bazează pe integrarea SwiftUI cu framework-ul Combine. Când ObservableObject își marchează proprietățile cu atributul @Published, SwiftUI se abonează automat la modificări prin publisher-ul încorporat în protocolul ObservableObject. La modificarea unei proprietăți publicate, obiectul trimite un semnal prin publisher-ul objectWillChange, ceea ce declanșează redesenarea tuturor View-urilor care observă acest obiect.

SwiftUI stochează instanța ObservableObject într-un depozit special legat de o anumită instanță View. Acest depozit este creat o dată la primul randament și există până la distrugerea View. Tocmai de aceea @StateObject garantează stabilitatea referinței la obiect — SwiftUI gestionează memoria automat, fără a se baza pe inițializatorul View.

Conform objc.io — Thinking in SwiftUI (2025), implementarea internă a @StateObject folosește un mecanism similar cu @State, dar pentru tipuri referință: SwiftUI creează o împachetare boxing în jurul obiectului și gestionează ciclul său de viață prin propriul alocator, optimizat pentru reconstruiri frecvente ale ierarhiei View.

Ciclul de viață al @StateObject

  • Creare — la prima apariție a View pe ecran, SwiftUI apelează inițializatorul obiectului și salvează referința.
  • Reconstruire — la actualizarea View-ului părinte, obiectul nu este recreat, se folosește instanța existentă.
  • Distrugere — când View părăsește ecranul și este eliminat din ierarhie, SwiftUI apelează deinit-ul obiectului.

@StateObject vs @ObservedObject: diferențe cheie

Diferența principală între @StateObject și @ObservedObject constă în cine deține obiectul. @StateObject creează și stochează obiectul — el este proprietarul. @ObservedObject doar observă un obiect care a fost creat în altă parte și transmis prin inițializator sau proprietate.

Caracteristică@StateObject@ObservedObject
DeținereCreează și deține obiectulDoar observă
InițializareÎn interiorul View prin init/defaultDin exterior, transmis prin parametru
Ciclul de viațăLegat de ciclul de viață al ViewNu este controlat de View
RecreereNu este recreat la actualizarePoate fi înlocuit din exterior
Versiune iOSiOS 14+iOS 13+

Regula este simplă: dacă View creează ObservableObject — folosește @StateObject. Dacă View doar primește un obiect deja gata de la părinte — folosește @ObservedObject. Încălcarea acestei reguli duce fie la pierderea datelor (dacă folosești @ObservedObject pentru deținere), fie la crearea excesivă de obiecte (dacă folosești @StateObject pentru observare).

Când să folosești @StateObject

@StateObject trebuie folosit în acele View-uri care sunt sursa de adevăr pentru un set specific de date. Scenariile tipice includ ecrane cu propriul view model, ecranele rădăcină ale stivelor de navigare și prezentările modale care își gestionează propria stare.

  • Ecran cu view model — fiecare ecran care își gestionează propriile date și logică ar trebui să își creeze view model-ul prin @StateObject.
  • View rădăcină — în ierarhia NavigationStack sau TabView, elementul rădăcină creează datele, iar copiii le primesc prin @ObservedObject.
  • Ferestre modale — .sheet și .fullScreenCover necesită adesea propriul @StateObject pentru gestionarea formularului sau procesului.
  • Listă cu editare — fiecare rând al listei care conține un formular de editare ar trebui să aibă propriul @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("Salvează") {
                    viewModel.saveProfile()
                }
            }
            .navigationTitle("Profile")
        }
    }
}

Inițializarea @StateObject cu parametri

Inițializarea @StateObject cu parametri necesită o sintaxă specială, deoarece SwiftUI gestionează crearea obiectului în mod independent. Nu poți pur și simplu transmite parametri în inițializator — trebuie să folosești o închidere escaping sau o metodă separată de creare.

Conform Swift by Sundell (2024), cea mai curată metodă este utilizarea unei metode fabrică sau a unei închideri pe care SwiftUI o va apela la prima creare a obiectului. O abordare alternativă — inițializarea ObservableObject în View-ul părinte și transmiterea lui prin @StateObject cu ajutorul inițializatorului 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)
    }
}

Este important de reținut că inițializatorul View cu @StateObject trebuie să folosească underscore înaintea numelui proprietății (_viewModel) pentru a accesa property wrapper-ul în sine, nu valoarea acestuia. Acesta este un model standard Swift pentru lucrul cu property wrapper-e în inițializatori.

Greșeli tipice cu @StateObject

Cea mai frecventă greșeală este utilizarea @ObservedObject în loc de @StateObject pentru View care ar trebui să dețină obiectul. În acest caz, la fiecare reconstruire a părintelui, obiectul va fi recreat, ceea ce duce la pierderea tuturor datelor acumulate. Această greșeală este deosebit de periculoasă în ierarhii complexe cu NavigationStack sau TabView.

  • Pierderea datelor la navigare — dacă un ecran copil folosește @ObservedObject pentru propriul view model, la revenire și redeschiudere datele se vor reseta.
  • Scurgere de memorie — crearea @StateObject într-un View părinte care nu este niciodată eliminat poate duce la acumularea de obiecte, dacă fiecare ecran copil creează și el @StateObject fără control.
  • Duplicarea obiectelor — transmiterea unui ObservableObject la mai multe @StateObject în View-uri diferite creează mai multe instanțe independente care nu se sincronizează între ele.

Pentru a evita aceste probleme, urmează regula simplă: un @StateObject pentru o sursă de adevăr. Dacă datele trebuie să fie comune între mai multe ecrane — creează @StateObject o dată în View-ul rădăcină și transmite-l prin @ObservedObject sau @EnvironmentObject elementelor copil.

swift
// ❌ Greșit: @ObservedObject pentru deținerea unui obiect
struct BadView: View {
    @ObservedObject var vm = ViewModel() // va fi recreat la fiecare actualizare!
}

// ✅ Corect: @StateObject pentru deținere
struct GoodView: View {
    @StateObject var vm = ViewModel() // creat o dată pentru durata de viață a View
}

Întrebări frecvente

Care este diferența dintre @StateObject și @State?

@State lucrează cu tipuri valoare (structuri, șiruri, numere) și stochează valoarea direct în depozitul SwiftUI. @StateObject lucrează cu tipuri referință — clase conforme cu ObservableObject. @State este potrivit pentru stări locale simple, @StateObject — pentru obiecte complexe cu logică și proprietăți publicate.

Pot folosi @StateObject în iOS 13?

Nu, @StateObject este disponibil doar de la iOS 14 în sus. Pentru iOS 13 folosește @ObservedObject și creează ObservableObject în View-ul părinte prin @State cu gestionare manuală a ciclului de viață. O alternativă — folosește @State cu struct în loc de class pentru datele care nu necesită semantică de referință.

Ce se întâmplă dacă folosesc @StateObject într-un View copil căruia obiectul îi este transmis de la părinte?

View-ul copil își va crea propria copie a ObservableObject, complet independentă de cea a părintelui. Modificările într-una nu se vor reflecta în cealaltă. Aceasta este aproape întotdeauna o greșeală: folosește @ObservedObject pentru a primi obiectul de la părinte și @StateObject doar pentru a crea un obiect nou în interiorul View.

Când este distrus obiectul creat prin @StateObject?

Obiectul este distrus când View-ul care l-a creat este complet eliminat din ierarhia SwiftUI. Pentru un ecran din NavigationStack, aceasta se întâmplă la pop de pe stiva de navigare. Pentru o fereastră modală — la închiderea acesteia. Pentru TabView — la schimbarea filei, dacă View nu este stocat în cache.

Cum transmit parametri la @StateObject la inițializare?

Folosește un init personalizat cu acces la property wrapper prin underscore: _viewModel = StateObject(wrappedValue: MyViewModel(param: value)). Acest model permite transmiterea oricăror parametri către ObservableObject, păstrând în același timp garanția creării unice a obiectului pe durata de viață a View.

Concluzii

  • @StateObject — property wrapper pentru crearea și deținerea ObservableObject în cadrul View, disponibil de la iOS 14.
  • Garanția creării unice — obiectul este inițializat o dată și nu este recreat la reconstruirea View.
  • Source of truth — @StateObject este sursa de adevăr, iar @ObservedObject doar observatorul.
  • Ciclul de viață — obiectul trăiește cât timp View există în ierarhia SwiftUI și este distrus la părăsirea acesteia.
  • Inițializarea cu parametri — necesită acces la property wrapper prin _viewModel și StateObject(wrappedValue:).
  • Greșeala de deținere — folosirea @ObservedObject pentru crearea obiectului duce la pierderea datelor la reconstruire.
  • Un obiect — un @StateObject — pentru date partajate, creează @StateObject în View-ul rădăcină și transmite-l copiilor prin @ObservedObject.

Vom dezvolta o aplicație mobilă la cheie

IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.

Discutați proiectul

Citiți și