@EnvironmentObject, SwiftUI'da bir property wrapper'dır ve hiyerarşideki herhangi bir View'in, başlatıcılar zinciri aracılığıyla açıkça iletmeden bir ObservableObject'e erişmesine olanak tanır. Nesne, .environmentObject() değiştiricisi kullanılarak hiyerarşinin belirli bir seviyesinde ortama enjekte edilir ve bundan sonra tüm alt View'ler @EnvironmentObject aracılığıyla ona erişebilir. Bu, nesneyi kullanmayan ara View'ler aracılığıyla nesneyi iletme ihtiyacını ortadan kaldırır — sözde prop drilling. John Sundell — Swift by Sundell (2025) tarafından yazılan bir makaleye göre, @EnvironmentObject özellikle çapraz ekran verileri için kullanışlıdır: kullanıcı oturumu, uygulama ayarları, alışveriş sepeti yöneticisi veya yerel veri önbelleği.
Önemli Noktalar
@EnvironmentObject, SwiftUI View'lerinin uygulamanın ortamından bir ObservableObject'e erişmesini sağlayan bir property wrapper'dır. Ortam, .environmentObject() değiştiricisi kullanılarak View hiyerarşisinin herhangi bir seviyesinde nesnelerin yerleştirilebildiği bir kapsayıcıdır. Bir nesne ortama yerleştirildiğinde, herhangi bir alt View, yalnızca @EnvironmentObject ile bir özellik bildirerek ve nesne türünü belirterek ona erişebilir.
@EnvironmentObject'in temel amacı, nesneyi her ara seviyeden geçirmek zorunda kalmadan derin bir View hiyerarşisi aracılığıyla veri aktarma sorununu çözmektir. NavigationStack, TabView ve modal pencerelerin dallandığı karmaşık uygulamalarda, @EnvironmentObject, kalıp kodunu ortadan kaldırarak mimariyi önemli ölçüde basitleştirir.
Apple Developer Documentation — Environment (2025)'e göre, @EnvironmentObject, PreferenceKey ve View tanımlamasına dayalı dahili bir SwiftUI mekanizması kullanır. Her View, üst View'den miras alınan ve .environmentObject() kullanılarak genişletilebilen kendi ortamına bir referans saklar. Nesne araması, kök View'e kadar hiyerarşide yukarı doğru gider.
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, SwiftUI'ya yerleşik bağımlılık enjeksiyonu (DI) mekanizmasına dayanarak çalışır. Bir View'de .environmentObject() çağırdığınızda, SwiftUI nesneyi o View ve tüm alt öğeleriyle ilişkili özel bir depolama alanında saklar. Bir alt View aynı türde @EnvironmentObject bildirdiğinde, SwiftUI üst hiyerarşide yukarı çıkarak ortamda nesneyi arar.
Önemli bir özellik — nesne türü, ortamda arama için anahtar olarak kullanılır. Ortamda aynı türde iki nesne varsa, SwiftUI hiyerarşide geçerli View'e en yakın olanı bulur. Nesne WindowGroup seviyesinde enjekte edildiğinde, uygulamanın tüm ekranları için küresel olarak kullanılabilir hale gelir, bu da genel amaçlı hizmetler için uygundur.
objc.io — SwiftUI Architecture (2025)'e göre, @EnvironmentObject dahili olarak @ObservedObject'e benzer bir mekanizma kullanır, ancak nesneyi hiyerarşide bulmak için ek bir soyutlama katmanıyla birlikte. SwiftUI nesneyi kopyalamaz veya yeni bir tane oluşturmaz — mevcut örneğe bir referans iletir, bu nedenle nesnedeki değişiklikler @EnvironmentObject kullanan tüm View'ler için otomatik olarak görünür olur.
Hem @EnvironmentObject hem de @ObservedObject aynı temel işlevi yerine getirir — bir ObservableObject'teki değişikliklere bir View'i abone yaparlar. Fark, nesne aktarım mekanizmasındadır. @ObservedObject, bir başlatıcı aracılığıyla açık aktarım gerektirirken, @EnvironmentObject, her ara View'de açıkça belirtilmeden nesneyi ortamdan alır.
| Özellik | @EnvironmentObject | @ObservedObject |
|---|---|---|
| Aktarım | Hiyerarşi seviyesinde .environmentObject() ile | Her View'in başlatıcısı aracılığıyla |
| Bağımlılık görünürlüğü | Gizli — View imzasında görünmez | Açık — View init'inde görünür |
| Ara View'ler | Nesneyi bilmez | Nesneyi daha fazla iletmelidir |
| Hata riski | Nesne eksik olduğunda Runtime crash | Derleme zamanı kontrolü (parametre zorunluysa) |
| Prop drilling | Ortadan kaldırır | Manuel aktarım gerektirir |
@EnvironmentObject ve @ObservedObject arasındaki seçim mimariye bağlıdır. Nesne hiyerarşinin derinliklerinde ve birçok ekranda gerekiyorsa — @EnvironmentObject daha uygundur. Mimari, test ve okunabilirlik için bağımlılıkların açıkça belirtilmesini gerektiriyorsa — @ObservedObject tercih edilir.
En yaygın senaryo, uygulamanın tüm ekranlarında erişilebilir olması gereken bir kullanıcı oturumudur. Uygulamanın kökünde .environmentObject() aracılığıyla UserSession enjekte edilerek, herhangi bir ekran kullanıcı verilerine ve yetkilendirme durumuna erişebilir.
struct ProfileView: View {
@EnvironmentObject var session: UserSession
var body: some View {
VStack {
if session.isLoggedIn {
Text("Hello, \(session.userName)")
Button("Logout") {
session.isLoggedIn = false
}
} else {
LoginView()
}
}
}
}
struct SettingsView: View {
@EnvironmentObject var session: UserSession
var body: some View {
Form {
Text("Logged in as \(session.userName)")
}
}
}
Ne ProfileView'in ne de SettingsView'in oturumu bir başlatıcı aracılığıyla almadığına dikkat edin. Sadece @EnvironmentObject var session: UserSession bildirirler ve SwiftUI otomatik olarak ortamda nesneyi bulur. Bu, mevcut veri aktarım kodunu değiştirmeden yeni ekranlar eklemeye olanak tanır.
@EnvironmentObject'in ana riski, nesne ortama enjekte edilmemişse runtime crash'dir. İsteğe bağlı parametrelerin aksine, @EnvironmentObject nil olamaz. @EnvironmentObject içeren bir View ekranda görünürse ve üst View bu tür için .environmentObject() çağırmamışsa, uygulama hemen “Fatal error: No ObservableObject of type X found” ile çöker.
Aynı türde iki nesneyi hiyerarşinin farklı seviyelerinde enjekte ederseniz, alt View hiyerarşideki en yakın olanı alır. Geliştirici, kök ortamdaki nesnenin, aynı türde bir nesneye sahip kendi ortamı olan bir modal pencerede kullanılabilir olmasını beklerse bu kafa karışıklığına yol açabilir.
SwiftUI'nin gelişmesiyle birlikte, @EnvironmentObject'in bazı eksikliklerini gideren alternatif bağımlılık yönetimi yaklaşımları ortaya çıkmıştır — başlıca bağımlılıkların örtüklüğü ve runtime crash riski.
Yaklaşım seçimi ekip büyüklüğüne ve uygulama karmaşıklığına bağlıdır. Küçük projeler için @EnvironmentObject harika çalışır. Düzinelerce ekranı ve sıkı test gereksinimleri olan büyük projeler için @ObservedObject veya bir DI kapsayıcısı aracılığıyla açık aktarım tercih edilir.
Sıkça Sorulan Sorular
Evet, bir View ihtiyaç duyduğu kadar farklı türde @EnvironmentObject bildirebilir. SwiftUI her türü ortamda bağımsız olarak arar. Bu, bir View'in aynı anda kullanıcı oturumuna, ayarlara ve alışveriş sepetine erişmesi gerektiğinde kullanışlıdır — her nesne ayrı ayrı enjekte edilir.
Preview, View'i görüntülemeye çalışırken bir runtime hatasıyla çöker. @EnvironmentObject kullanan View'ler için Preview'de her zaman .environmentObject() ekleyin. Preview'in doğru çalışması ve gerçekçi bir durum göstermesi için test verileriyle sahte nesneler kullanın.
Hayır, @EnvironmentObject yalnızca ObservableObject'e uyan somut bir sınıf türüyle çalışır. Protokoller için type erasure veya bir sarmalayıcı kullanmanız gerekir: protokol türündeki nesneye bir referans tutan bir sarmalayıcı sınıf oluşturun ve sarmalayıcıyı @EnvironmentObject aracılığıyla enjekte edin.
Test verileriyle bir ObservableObject örneği oluşturun ve testte .environmentObject(testObject) aracılığıyla View'e iletin. Bu, SwiftUI UI testleri için standart desendir. Birim testleri için, mantığı ObservableObject'te yalıtın ve View'den ayrı olarak test edin.
@EnvironmentObject, nesnenin bir kopyasını değil, yalnızca bir referansını ilettiği için ek performans yükü oluşturmaz. Ancak, küresel bir nesnedeki @Published özelliklerinin sık güncellenmesi, birçok View'in aynı anda yeniden çizilmesine neden olabilir ve bu da performansı etkileyebilir.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun