SwiftUI: StateObject

SwiftUI görünümleri arasında güvenli bir şekilde veri transferi yapmamızı sağlayan StateObject property wrapper’ını keşfedin!

M. Bertan Tarakçıoğlu
TurkishKit
3 min readJul 21, 2021

--

👋🏻 Hepinize yeniden merhaba sevgili TurkishKit okurları! Bu yazımızda sizlerle birlikte SwiftUI’ın ObservableObject‘ini keşfediyoruz. Hadi başlayalım!

🚀 Giriş

Eğer bir süredir SwiftUI ile çalışıyorsanız, büyük ihtimalle daha önce farklı görünümler arasında veri aktarmak için ObservedObject de kullanmışsınızdır. Eğer kullanmadıysanız da hiç sorun değil, onunla ilgili de harika bir yazımız bulunmakta. 😎

iOS 14 ve sonrasında kullanılabilen StateObject de temelde ObservedObject ile aynı görevi üstleniyor, ancak çok daha güvenli.

Çoğunlukla ObservedObject işimizi mükemmel bir şekilde görse de nadiren kodumuz çökebiliyor. Bunun nedeni SwiftUI’ın görünüm struct‘larını istediği zaman yok edip yeniden oluşturmakta özgür olması. 😳 Kulağa biraz garip gelebilir, ama aslında böyle olması oldukça mantıklı.

Bir NavigationView düşünelim. Kullanıcı beşinci sayfaya geldiğinde SwiftUI ilk sayfayı bellek harcamamak için yok edip, kullanıcı ilk sayfaya geri döndüğünde yeniden oluşturmak isteyebilir. Çünkü sistem için bir struct oluşturmak oldukça kolay, ama bellek alanı oldukça değerli. Sorun, ilk sayfa yok olduğunda içindeki ObservedObject değişkenin de yok olması. Değişkenimiz yok olduğunda da uygulamamız çöküyor.

Bazı durumlarda ise struct içerisindeki body elemanı daha ObservedObject değişkeni oluşturulmadan çalışıyor. Değişken daha oluşmadan body içerisinde kullandığımızda da sonuç yine aynı. 😅

Bu durumlarda yardımımıza StateObject koşuyor. StateObject kullandığımızda SwiftUI bize değişkenin kesinlikle body çalışmaya başlamadan önce yaratılacağının, ve görünüm yok edilse bile kendisinin yok edilmeyeceğinin garantisini veriyor. Böylece yukarıdaki iki kötü durum senaryosu da imkansız hale geliyor.

🔨 StateObject Kullanımı

Sanırım StateObject‘in en iyi yanı da kullanımının neredeyse ObservedObject ile aynı oluşu! Tek farkı değişkenimizi tanımlarken @ObservedObject yerine @StateObject Property Wrapper’ını kullanıyor olmamız. Merak etmeyin, aşağıda bir StateObject oluşturmak için takip etmeniz gereken bütün adımları sıfırdan açıklıyorum. 🙂

StateObject ‘in temel amacı farklı görünümler arasında veri paylaşımı yapmak ve paylaşılan verilerde bir değişiklik olması durumunda verileri kullanan görünümlerin güncellenmesini sağlamak. Bu örnekte kullanıcı adını farklı görünümler arasında paylaşacağız. Hadi başlayalım!

İlk adım ObservableObject protokolüne uyan bir sınıf oluşturmak — kullanıcı adını bu veri tipi içinde tutacağız. Kullanıcı imi değişkenimizin başına @Published property wrapper’ını ekliyoruz. Bu, StateObject değişkenini kullanan görünümlerimizin kullanıcı adı değiştiğinde kendilerini otomatik olarak güncellemelerini sağlayacak.

final class UserData: ObservableObject {
@Published var userName = ""
}

Şimdi de sıra görünümlerimizi oluşturmakta! Uygulamamız oldukça basit olacak: bir NavigationView içinde ilk sayfada kullanıcının ismini sorulacak ve ikinci sayfada isim kullanarak bir hoşgeldin mesajı gösterilecek.

Eğer dikkat ettiyseniz her iki görünümümüzde de StateObject yerine EnvironmentObject kullandık. Bunu sebebi birazdanUserData objemizi ilk defa App objesi üzerinde oluşturup FirstView üzerine EnvironmentObject olarak atayacak olmamız — aynı buradaki NavigationLink içerisinde SecondView görünümüne yaptığımız gibi!

struct FirstView: View {
@EnvironmentObject private var userData: UserData
var body: some View {
VStack {
HStack {
Text(“Lütfen isminizi girin:”)
.foregroundColor(.mint)
.font(.title3)
TextField(“İsminiz”, text: $userData.userName)
.textFieldStyle(.roundedBorder)
}
.padding()
NavigationLink(
destination:
SecondView()
.environmentObject(userData)

){
Label(“Sonraki”, systemImage: “arrow.right”)
.font(.title3)
}
}
.navigationTitle(“Merhaba!”)
}
}
struct SecondView: View {
@EnvironmentObject private var userData: UserData
var body: some View {
Label(“Hoşgeldin, \(userData.userName)!”, systemImage: “face.smiling”)
.foregroundColor(.yellow)
.font(.title)
}
}

Şimdi de sıra biraz önce bahsettiğim gibi App sınıfında StateObject değişkenimizi oluşturup FirstView görünümüne environmentObject niteleyicisini kullanarak EnvironmentObject olarak atamak. Tabii NavigationView objesini de unutmuyoruz. 🙂

@main
struct
TurkishKit_TutorialsApp: App {
@StateObject private var userData = UserData()
var body: some Scene {
WindowGroup {
NavigationView {
FirstView()
.environmentObject(userData)
}
}
}
}
Sırasıyla ilk ve ikinci sayfalar.

İşte hepsi bu kadar! Umarım öğrendikleriniz sizin için faydalı olmuştur. Görüşmek üzere, kendinize iyi bakın. 🙂

Bizi daha yakından takip etmek istiyorsanız, sosyal medya hesaplarımıza aşağıdan ulaşabilirsiniz!

Twitter | Instagram | Facebook

--

--

M. Bertan Tarakçıoğlu
TurkishKit

18, He/Him, Incoming CS at Stevens Institute of Technology, IBDP Graduate, Apple Developer, Maker, Three-Time Apple WWDC Scholar, MUN Delegate