@EnvironmentObject — adalah property wrapper di SwiftUI yang memungkinkan View mana pun dalam hierarki mengakses ObservableObject tanpa pengiriman eksplisit melalui rantai inisialisator. Objek diinjeksikan ke dalam lingkungan menggunakan pengubah .environmentObject() pada tingkat hierarki tertentu, setelah itu semua View turunan dapat memperolehnya melalui @EnvironmentObject. Ini menghilangkan kebutuhan untuk mengirimkan objek melalui View perantara yang tidak menggunakannya — yang disebut prop drilling. Menurut artikel John Sundell — Swift by Sundell (2025), @EnvironmentObject sangat berguna untuk data lintas layar: sesi pengguna, pengaturan aplikasi, manajer keranjang belanja, atau cache data lokal.
Poin Utama
@EnvironmentObject — adalah property wrapper yang memungkinkan SwiftUI View mengakses ObservableObject dari lingkungan (environment) aplikasi. Lingkungan adalah wadah tempat Anda dapat menempatkan objek di tingkat mana pun dari hierarki View menggunakan pengubah .environmentObject(). Setelah objek ditempatkan di lingkungan, View turunan mana pun dapat memperolehnya hanya dengan mendeklarasikan properti dengan @EnvironmentObject dan menentukan tipe objek.
Tugas utama @EnvironmentObject — memecahkan masalah pengiriman data melalui hierarki View yang dalam tanpa perlu mengirimkan objek melalui setiap tingkat perantara. Dalam aplikasi kompleks dengan struktur NavigationStack, TabView, dan jendela modal yang bercabang, @EnvironmentObject secara signifikan menyederhanakan arsitektur dengan menghilangkan kode boilerplate.
Menurut Apple Developer Documentation — Environment (2025), @EnvironmentObject menggunakan mekanisme internal SwiftUI yang didasarkan pada PreferenceKey dan identifikasi View. Setiap View menyimpan referensi ke lingkungannya sendiri, yang diwarisi dari View induk dan dapat diperluas dengan .environmentObject(). Pencarian objek dilakukan ke atas melalui hierarki hingga ke View akar.
class UserSession: ObservableObject {
@Published var isLoggedIn = false
@Published var userName: String = ""
func login(name: String) {
userName = name
isLoggedIn = true
}
}
@main
struct MyApp: App {
@StateObject var session = UserSession()
var body: some Scene {
WindowGroup {
ContentView()
.environmentObject(session)
}
}
}
@EnvironmentObject bekerja berdasarkan mekanisme injeksi dependensi (DI) yang tertanam di SwiftUI. Ketika Anda memanggil .environmentObject() pada View, SwiftUI menyimpan objek di penyimpanan khusus yang terkait dengan View ini dan semua turunannya. Ketika View turunan mendeklarasikan @EnvironmentObject dari tipe yang sama, SwiftUI mencari objek di lingkungan, naik melalui hierarki induk.
Fitur penting — tipe objek digunakan sebagai kunci untuk pencarian di lingkungan. Jika ada dua objek dengan tipe yang sama di lingkungan, SwiftUI akan menemukan yang terdekat dengan View saat ini dalam hierarki. Saat menginjeksikan objek di tingkat WindowGroup, objek menjadi tersedia secara global untuk semua layar aplikasi, yang nyaman untuk layanan tujuan umum.
Menurut objc.io — SwiftUI Architecture (2025), secara internal @EnvironmentObject menggunakan mekanisme yang mirip dengan @ObservedObject, tetapi dengan tingkat abstraksi tambahan untuk menemukan objek dalam hierarki. SwiftUI tidak menyalin objek dan tidak membuatnya — ia mengirimkan referensi ke instance yang ada, sehingga perubahan pada objek secara otomatis terlihat oleh semua View yang menggunakan @EnvironmentObject.
Baik @EnvironmentObject maupun @ObservedObject menjalankan fungsi dasar yang sama — mereka berlangganan View ke perubahan ObservableObject. Perbedaannya terletak pada mekanisme pengiriman objek. @ObservedObject memerlukan pengiriman eksplisit melalui inisialisator, sedangkan @EnvironmentObject mendapatkan objek dari lingkungan tanpa menentukan secara eksplisit di setiap View perantara.
| Karakteristik | @EnvironmentObject | @ObservedObject |
|---|---|---|
| Pengiriman | Melalui .environmentObject() di tingkat hierarki | Melalui inisialisator setiap View |
| Kejelasan dependensi | Tersembunyi — tidak terlihat di signature View | Eksplisit — terlihat di init View |
| View perantara | Tidak tahu tentang objek | Harus mengirimkan objek lebih lanjut |
| Risiko kesalahan | Runtime crash saat objek tidak ada | Pemeriksaan waktu kompilasi (jika parameter wajib) |
| Prop drilling | Menghilangkan | Memerlukan pengiriman manual |
Pilihan antara @EnvironmentObject dan @ObservedObject tergantung pada arsitektur. Jika objek diperlukan jauh di dalam hierarki dan untuk banyak layar — @EnvironmentObject lebih nyaman. Jika arsitektur memerlukan penentuan dependensi secara eksplisit untuk pengujian dan keterbacaan — @ObservedObject lebih disukai.
Skenario yang paling umum — sesi pengguna, yang harus tersedia di semua layar aplikasi. Dengan menginjeksikan UserSession melalui .environmentObject() di akar aplikasi, layar mana pun dapat mengakses data pengguna dan status otorisasi.
struct ProfileView: View {
@EnvironmentObject var session: UserSession
var body: some View {
VStack {
if session.isLoggedIn {
Text("Halo, \(session.userName)")
Button("Keluar") {
session.isLoggedIn = false
}
} else {
LoginView()
}
}
}
}
struct SettingsView: View {
@EnvironmentObject var session: UserSession
var body: some View {
Form {
Text("Masuk sebagai \(session.userName)")
}
}
}
Perhatikan: baik ProfileView maupun SettingsView tidak menerima session melalui inisialisator. Mereka hanya mendeklarasikan @EnvironmentObject var session: UserSession, dan SwiftUI secara otomatis menemukan objek di lingkungan. Ini memungkinkan penambahan layar baru tanpa mengubah kode pengiriman data yang ada.
Risiko utama @EnvironmentObject — runtime crash jika objek tidak diinjeksikan ke lingkungan. Tidak seperti parameter opsional, @EnvironmentObject tidak bisa nil. Jika View dengan @EnvironmentObject muncul di layar, dan View induk tidak memanggil .environmentObject() untuk tipe ini, aplikasi akan segera crash dengan "Fatal error: No ObservableObject of type X found".
Jika Anda menginjeksikan dua objek dengan tipe yang sama di tingkat hierarki yang berbeda, View turunan akan menerima yang terdekat dalam hierarki. Ini dapat menyebabkan kebingungan jika pengembang mengharapkan objek dari lingkungan akar tersedia di jendela modal yang memiliki lingkungan sendiri dengan objek dengan tipe yang sama.
Seiring perkembangan SwiftUI, muncul cara alternatif untuk mengelola dependensi yang mengatasi beberapa kekurangan @EnvironmentObject — terutama ketidakjelasan dependensi dan risiko runtime crash.
Pilihan pendekatan tergantung pada ukuran tim dan kompleksitas aplikasi. Untuk proyek kecil @EnvironmentObject bekerja dengan sangat baik. Untuk proyek besar dengan puluhan layar dan persyaratan pengujian yang ketat, pengiriman eksplisit melalui @ObservedObject atau wadah DI lebih disukai.
Pertanyaan yang Sering Diajukan
Ya, View dapat mendeklarasikan sebanyak mungkin @EnvironmentObject dari tipe yang berbeda. SwiftUI mencari setiap tipe secara independen di lingkungan. Ini berguna ketika View membutuhkan akses ke sesi pengguna, pengaturan, dan keranjang belanja secara bersamaan — setiap objek diinjeksikan secara terpisah.
Preview akan crash dengan runtime error saat mencoba menampilkan View. Selalu tambahkan .environmentObject() di Preview untuk View yang menggunakan @EnvironmentObject. Gunakan objek mock dengan data tes agar Preview berfungsi dengan benar dan menampilkan keadaan yang realistis.
Tidak, @EnvironmentObject hanya bekerja dengan tipe kelas konkret yang mengimplementasikan ObservableObject. Untuk protokol, Anda harus menggunakan type erasure atau pembungkus: buat kelas pembungkus yang menyimpan referensi ke objek bertipe protokol dan injeksikan pembungkus melalui @EnvironmentObject.
Buat instance ObservableObject dengan data tes dan kirimkan ke View melalui .environmentObject(testObject) dalam tes. Ini adalah pola standar untuk pengujian UI di SwiftUI. Untuk pengujian unit, isolasi logika di ObservableObject dan uji secara terpisah dari View.
@EnvironmentObject tidak menciptakan beban kinerja tambahan, karena hanya mengirimkan referensi ke objek, bukan menyalinnya. Namun, pembaruan yang sering pada properti @Published di objek global dapat menyebabkan banyak View digambar ulang secara bersamaan, yang dapat mempengaruhi kinerja.
Ringkasan
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.
Baca juga