@StateObject: apa itu, perbedaan dari @ObservedObject dan contoh

Penulis: IT Sectr Diterbitkan: 2026-06-19 Waktu membaca: 7 mnt

@StateObject adalah Property Wrapper di SwiftUI untuk membuat dan memiliki instance ObservableObject langsung di view. SwiftUI menjamin bahwa objek diinisialisasi satu kali selama siklus hidup tampilan dan tidak dibuat ulang saat render berulang. Menurut Apple Developer Documentation (2025), @StateObject direkomendasikan untuk view akar yang membuat sumber data. @StateObject adalah pilihan tepat untuk memiliki ObservableObject dalam hierarki SwiftUI.

Poin Utama

  • @StateObject — Property Wrapper untuk membuat dan memiliki ObservableObject di view
  • Instance tunggal — objek dibuat sekali dan tidak dibuat ulang saat render
  • Sumber kebenaran — @StateObject menjamin stabilitas data untuk seluruh hierarki
  • Perbedaan dari @ObservedObject — @ObservedObject tidak memiliki objek dan bisa kehilangannya
  • View akar — @StateObject digunakan di view yang membuat objek

Apa itu @StateObject di SwiftUI?

@StateObject adalah Property Wrapper yang muncul di SwiftUI 2.0 (iOS 14) yang menggabungkan kemampuan @ObservedObject dan @State. Seperti @ObservedObject, ia berlangganan perubahan ObservableObject. Seperti @State, ia menjamin bahwa data bertahan dari inisialisasi berulang struktur view. @StateObject membuat objek sekali saat pertama kali view muncul di layar dan menyimpannya di heap SwiftUI.

Sebelum munculnya @StateObject, pengembang menggunakan @ObservedObject untuk semua ObservableObject, termasuk yang dibuat di view. Ini menyebabkan seringnya kehilangan data saat view induk diperbarui, ketika struktur view dibuat ulang, membawa serta instance @ObservedObject. @StateObject memecahkan masalah ini dengan menambahkan jaminan stabilitas.

Aturan utama: @StateObject diterapkan di view yang membuat objek di inisialisator default (let model = ViewModel()). View anak yang menerima objek ini menggunakan @ObservedObject. Pemisahan semacam itu menjamin satu sumber kebenaran di seluruh hierarki.

Siklus hidup @StateObject

SwiftUI mengelola siklus hidup @StateObject melalui manajer penyimpanan, mirip dengan @State. Saat pertama kali view muncul, SwiftUI mengalokasikan memori untuk objek dan menyimpannya di area persisten. Saat render berulang (pemanggilan body), objek tidak dibuat ulang — instance yang ada digunakan. Objek hidup selama view berada dalam hierarki.

Ketika view dihapus dari hierarki, SwiftUI menghancurkan @StateObject, memanggil deinit. Saat view ditambahkan kembali ke hierarki, instance baru dibuat. Ini penting dipertimbangkan saat merancang: jika perlu menyimpan data di antara penghapusan view, gunakan lapisan layanan (singleton atau DI) atau @AppStorage untuk persistensi.

swift
class TimerViewModel: ObservableObject {
    @Published var seconds: Int = 0
    private var timer: Timer?

    func start() {
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { _ in
            self.seconds += 1
        }
    }

    deinit {
        timer?.invalidate()
    }
}

struct TimerView: View {
    @StateObject var viewModel = TimerViewModel()

    var body: some View {
        Text("\(viewModel.seconds)s")
            .onAppear { viewModel.start() }
    }
}

Dalam contoh, TimerViewModel dibuat melalui @StateObject dan hidup selama TimerView di layar. Timer dimulai di onAppear dan berhenti di deinit. Jika @ObservedObject digunakan, setiap render TimerView akan membuat TimerViewModel baru dengan detik = 0 dan timer tidak akan pernah berfungsi dengan benar. @StateObject menjamin bahwa viewModel unik dan stabil.

@StateObject vs @ObservedObject: perbandingan

Pilihan antara @StateObject dan @ObservedObject tergantung pada siapa yang memiliki objek. Jika view membuat objek — @StateObject. Jika view menerima objek jadi — @ObservedObject. Aturan ini sangat penting sehingga Xcode mengeluarkan peringatan saat menggunakan @StateObject di view anak yang menerima objek melalui inisialisator.

SituasiWrapper yang direkomendasikan
View membuat model melalui ViewModel()@StateObject
View menerima model dari induk@ObservedObject
Model digunakan di satu view@StateObject
Model diteruskan melalui Environment@EnvironmentObject
Model diperlukan untuk pratinjau@ObservedObject + mock

Dalam praktiknya, di awal proyek sering digunakan @StateObject di view akar dan @ObservedObject di semua view anak. Seiring pertumbuhan aplikasi, sebagian @StateObject dapat diganti dengan @EnvironmentObject untuk menyederhanakan hierarki. Namun, @StateObject tetap menjadi pilihan terbaik untuk layar modular dengan logika sendiri.

Pola penggunaan @StateObject

Pola pertama — MVVM dengan @StateObject. ViewModel sebagai ObservableObject dibuat di view melalui @StateObject. ViewModel berisi properti @Published dan logika bisnis. View berlangganan perubahan dan memperbarui antarmuka. Pendekatan ini memberikan isolasi yang dapat diuji: ViewModel dapat diuji tanpa UI dengan membuat instance secara langsung.

Pola kedua — @StateObject dengan dependensi. Jika ViewModel memerlukan layanan, gunakan inisialisasi dengan parameter. Misalnya, @StateObject var viewModel = UserViewModel(api: APIClient.shared). Namun berhati-hatilah: parameter dihitung setiap kali render body, tetapi objek dibuat hanya sekali. SwiftUI mengabaikan inisialisasi @StateObject berikutnya.

Pola ketiga — @StateObject bersarang. Di SwiftUI, Anda dapat memiliki beberapa @StateObject dalam satu view, tetapi ini jarang dibenarkan. Biasanya satu @StateObject bertanggung jawab atas seluruh kumpulan data view. Jika logika menjadi terlalu kompleks, pecahlah menjadi komposisi layanan @ObservedObject di dalam satu @StateObject.

swift
struct AppView: View {
    @StateObject var router = NavigationRouter()
    @StateObject var auth = AuthViewModel()

    var body: some View {
        ContentView()
            .environmentObject(router)
            .environmentObject(auth)
    }
}

Dalam contoh, AppView membuat dua @StateObject: NavigationRouter untuk mengelola navigasi dan AuthViewModel untuk autentikasi. Kedua objek disuntikkan ke Environment melalui environmentObject. Setiap view anak dapat mengaksesnya melalui @EnvironmentObject tanpa melewati rantai inisialisator.

@StateObject dan inisialisasi dengan parameter

@StateObject mendukung inisialisasi dengan parameter apa pun, tetapi dengan fitur penting: inisialisator dipanggil hanya sekali. Saat render ulang body, nilai baru parameter diabaikan. Ini berarti jika Anda meneruskan @State var id: Int = 5 ke @StateObject var vm = ViewModel(id: id), saat id berubah, ViewModel tidak akan menerima nilai baru.

Untuk mengatasi masalah ini, gunakan onReceive atau onAppear untuk sinkronisasi. Berlangganlah perubahan parameter di dalam ViewModel melalui Combine atau teruskan parameter melalui metode .onChange(of:) di tingkat view. Alternatif — gunakan @ObservedObject alih-alih @StateObject jika objek harus bereaksi secara dinamis terhadap perubahan eksternal.

swift
struct DetailView: View {
    let itemId: Int
    @StateObject var viewModel = DetailViewModel()

    var body: some View {
        Text(viewModel.title)
            .onAppear { viewModel.load(id: itemId) }
    }
}

Pendekatan yang benar: DetailView menerima itemId sebagai properti let (diteruskan melalui inisialisator struktur), dan @StateObject membuat DetailViewModel tanpa parameter. Di onAppear, metode load(id:) dipanggil, yang memuat data untuk ID yang diteruskan. Ini menjamin bahwa ViewModel dibuat oleh mekanisme @StateObject, tetapi data dimuat setiap kali view muncul dengan ID saat ini.

Kesalahan umum dengan @StateObject

Kesalahan utama — menggunakan @StateObject di view anak yang menerima objek dari induk. Jika ParentView membuat @StateObject model, dan ChildView mendeklarasikan @StateObject var model: ModelType (dengan parameter default), maka ChildView akan membuat instance independen sendiri. Objek induk dan anak tidak akan terhubung, dan perubahan di satu objek tidak akan tercermin di objek lainnya.

Kesalahan kedua — menempatkan @StateObject di List atau ForEach. Setiap elemen daftar membuat @StateObject sendiri, yang mengarah ke banyak instance independen. Untuk daftar, yang benar adalah meneruskan satu ObservableObject ke semua elemen melalui @ObservedObject atau menggunakan struktur Identifiable dengan @State di dalam List.

Masalah ketiga — kurangnya pembersihan di deinit. @StateObject hidup sepanjang siklus hidup view. Jika objek membuat timer, langganan Combine, atau permintaan jaringan, deinit harus membatalkannya. Jika tidak, kebocoran memori dan kelanjutan pekerjaan latar belakang setelah layar ditutup tidak dapat dihindari. Selalu gunakan Cancellable store Combine atau invalidate timer di deinit.

Pertanyaan yang Sering Diajukan

Kapan @StateObject muncul di SwiftUI?

@StateObject ditambahkan di SwiftUI 2.0 pada WWDC 2020 bersama dengan iOS 14, macOS 11, watchOS 7, dan tvOS 14. Sebelumnya, @ObservedObject adalah satu-satunya cara bekerja dengan ObservableObject, yang menyebabkan seringnya bug kehilangan data.

Bisakah @StateObject menjadi opsional?

Tidak, @StateObject tidak mendukung tipe Optional. Objek harus diinisialisasi saat deklarasi. Jika Anda membutuhkan objek opsional, gunakan @ObservedObject atau @EnvironmentObject dengan tipe opsional.

Bagaimana cara memeriksa bahwa @StateObject hanya dibuat sekali?

Tambahkan print(#function) di inisialisator dan deinit ObservableObject. Jika init tidak dipanggil saat render ulang — @StateObject berfungsi dengan benar. Jika init dipanggil setiap kali — ganti @ObservedObject dengan @StateObject.

Bisakah saya menggunakan @StateObject dengan UIKit melalui UIHostingController?

Ya, @StateObject berfungsi di view SwiftUI yang disematkan di UIKit melalui UIHostingController. Siklus hidup objek terikat ke view SwiftUI, bukan ke UIViewController. Jika view SwiftUI diganti, @StateObject dihancurkan.

Mana yang lebih baik: satu @StateObject dengan ViewModel besar atau beberapa kecil?

Beberapa @StateObject kecil dengan tanggung jawab terpisah. Ini meningkatkan kemampuan uji, penggunaan kembali, dan kinerja — saat satu objek berubah, hanya bagian antarmuka yang berlangganan yang digambar ulang, bukan seluruh view.

Ringkasan

  • @StateObject — Property Wrapper untuk membuat dan memiliki ObservableObject di view
  • Instance tunggal — objek tidak dibuat ulang saat render ulang body
  • Sumber kebenaran — @StateObject di view akar menjamin stabilitas data untuk hierarki
  • Aturan pemilihan — @StateObject untuk membuat, @ObservedObject untuk menerima objek jadi
  • Inisialisasi — parameter di @StateObject dihitung sekali, pembaruan tidak dilacak
  • Deinit — pembersihan wajib timer dan langganan di deinit ObservableObject
  • iOS 14+ — @StateObject tersedia mulai iOS 14, macOS 11, watchOS 7, tvOS 14

Kami akan mengembangkan aplikasi seluler turnkey

IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.

Diskusikan proyek

Baca juga