SwiftUI, bildirimsel bir UI framework'ü olarak state yönetimini merkeze alır. MVVM (Model-View-ViewModel) mimarisi, SwiftUI projelerinde state'i düzenli ve test edilebilir tutmanın en yaygın yoludur. Bu yazıda, @StateObject, @ObservedObject, @EnvironmentObject gibi temel property wrapper'ların MVVM içinde nasıl kullanılacağını, sık yapılan hataları ve uygulanabilir bir kontrol listesini bulacaksınız.
MVVM ve SwiftUI Property Wrapper'ları
MVVM'de ViewModel, View'in ihtiyaç duyduğu tüm state'i ve iş mantığını barındırır. SwiftUI, ViewModel'i gözlemlemek için @StateObject, @ObservedObject ve @EnvironmentObject sağlar. Doğru wrapper seçimi, performans ve veri akışı açısından kritiktir.
@StateObject vs @ObservedObject
@StateObject, bir View içinde ViewModel'in ilk kez oluşturulduğu ve yaşam döngüsünün View'e bağlı olduğu durumlarda kullanılır. View yeniden oluşturulsa bile state kaybolmaz. @ObservedObject ise ViewModel'in dışarıdan (örneğin bir parent View'den) enjekte edildiği durumlar içindir. View her yeniden oluşturulduğunda state sıfırlanmaz, ancak ViewModel'in ömrü parent tarafından yönetilir.
@EnvironmentObject ve Paylaşılan State
Bir ViewModel'in uygulama genelinde paylaşılması gerektiğinde @EnvironmentObject idealdir. Örneğin, kullanıcı oturumu veya tema ayarları gibi global state'ler için kullanılır. View hiyerarşisinde .environmentObject(viewModel) ile sağlanır ve alt View'lerde @EnvironmentObject ile erişilir.
Pratik İpuçları
- ViewModel'i ObservableObject protokolüne uygun tanımlayın: State değişikliklerini yayınlamak için
@Publishedproperty'leri kullanın. ViewModel'in içinde iş mantığını ve network çağrılarını tutun; View sadece veriyi görüntülesin. - @StateObject'i yalnızca ViewModel'i ilk kez oluştururken kullanın: Parent View'den gelen bir ViewModel için
@ObservedObjecttercih edin. Yanlış kullanım, View yeniden oluşturulduğunda state kaybına yol açabilir. - Büyük ViewModel'leri parçalayın: Tek bir ViewModel'de çok fazla state ve iş mantığı birikmesi, test edilebilirliği zorlaştırır. Örneğin, bir liste View'i için ayrı bir ListViewModel, detay View'i için ayrı bir DetailViewModel oluşturun.
- @EnvironmentObject'i dikkatli kullanın: Tüm uygulamaya yayılan state'ler için idealdir ancak her View'in bu state'e ihtiyacı yoksa, gereksiz yeniden çizimlere sebep olabilir. Sadece ihtiyaç duyan View'lere iletin.
- Combine ve async/await entegrasyonu: ViewModel içinde Combine yayıncıları veya async/await fonksiyonları kullanarak network isteklerini yönetin. Flutter'da Dio ile HTTP İstekleri Yönetimi yazısındaki gibi benzer prensipler SwiftUI'da da geçerlidir.
- Hata yönetimini ViewModel'e taşıyın: API çağrılarından dönen hataları ViewModel içinde işleyin ve kullanıcıya gösterilecek state'i güncelleyin. REST API Hata Yönetimi rehberindeki yaklaşımları SwiftUI'a uyarlayabilirsiniz.
- Performans için identity kullanın: Listelerde
ForEachile çalışırken her öğeye benzersiz biridverin. ViewModel'deIdentifiableprotokolünü uygulayın.
Sık Yapılan Hatalar ve Kaçınılması Gerekenler
- @StateObject'i birden fazla View'de kullanmak: Aynı ViewModel örneğini bir parent View'de @StateObject ile oluşturup child View'lara aktarmak yerine, child'larda @ObservedObject kullanın. Aksi halde her child kendi ViewModel'ini oluşturur ve state senkronizasyonu bozulur.
- ViewModel içinde UIKit veya SwiftUI'ya ait referansları tutmak: ViewModel platformdan bağımsız olmalıdır. UI nesnelerini ViewModel'de tutmak test edilebilirliği azaltır ve bellek sızıntılarına yol açar.
- @Published property'leri gereksiz yere fazla kullanmak: Her küçük değişiklik için @Published kullanmak, gereksiz yeniden çizimlere neden olur. Sadece UI'ın güncellenmesi gereken durumları @Published yapın.
MVVM State Yönetimi Kontrol Listesi
- ☐ ViewModel, ObservableObject protokolünü uyguluyor ve @Published property'ler doğru tanımlanmış.
- ☐ ViewModel'in ilk oluşturulduğu View'de @StateObject, diğerlerinde @ObservedObject kullanılıyor.
- ☐ Global state'ler (oturum, tema) @EnvironmentObject ile sağlanıyor ve sadece ihtiyaç duyan View'lere iletilmiş.
- ☐ ViewModel içinde UI nesnesi referansı yok; tüm iş mantığı Combine veya async/await ile yönetiliyor.
- ☐ Hata durumları ViewModel'de işleniyor ve kullanıcıya anlamlı mesajlar gösteriliyor.
- ☐ Listelerde ForEach kullanılıyor ve her öğe Identifiable protokolünü uyguluyor.
- ☐ ViewModel'ler parçalanmış; her View için ayrı bir ViewModel oluşturulmuş.
- ☐ Bellek sızıntısını önlemek için weak referanslar ve DisposeBag (ya da Cancellable set) kullanılıyor.
- ☐ ViewModel, Unit Test ile test edilebilir durumda; bağımlılıklar enjekte edilebiliyor.
Sonuç
SwiftUI'da MVVM ile state yönetimi, doğru property wrapper'lar seçildiğinde ve yukarıdaki ipuçları takip edildiğinde oldukça verimlidir. Uygulamanızın ölçeğine göre state yönetimini sadeleştirin ve test edilebilirliği ön planda tutun. API seçiminde kararsız kalırsanız, GraphQL vs REST karşılaştırmasına göz atabilirsiniz. Unutmayın: SwiftUI, state odaklıdır; state'inizi iyi yönetirseniz UI otomatik olarak güncellenir.
Sık Sorulan Sorular
SwiftUI'da @StateObject ve @ObservedObject arasındaki temel fark nedir?
@StateObject bir View içinde ilk kez oluşturulan ViewModel için kullanılır ve View yeniden oluşturulsa bile state korunur. @ObservedObject ise dışarıdan enjekte edilen ViewModel'ler için kullanılır ve ViewModel'in yaşam döngüsü parent View'e bağlıdır.
MVVM mimarisinde ViewModel'de UIKit referansı tutmak neden yanlıştır?
ViewModel platformdan bağımsız olmalıdır; UIKit referansı tutmak test edilebilirliği düşürür, bellek sızıntılarına yol açar ve SwiftUI'un bildirimsel yapısıyla uyumsuzdur. UI işlemleri View katmanında kalmalıdır.
@EnvironmentObject hangi durumlarda kullanılmalıdır?
@EnvironmentObject, uygulama genelinde paylaşılan global state'ler için idealdir. Örneğin kullanıcı oturumu, tema ayarları veya dil tercihi gibi birçok View'in erişmesi gereken verilerde kullanılır. Sadece ihtiyaç duyan View'lere iletilmelidir.
SwiftUI'da ViewModel'leri parçalamak neden önemlidir?
Büyük ViewModel'ler bakımı zorlaştırır, test edilebilirliği azaltır ve gereksiz yeniden çizimlere neden olabilir. Her View için ayrı bir ViewModel oluşturmak, sorumlulukları netleştirir ve kodun modüler kalmasını sağlar.






